20240420 测试 笔记
T1
题意
有
分析
由于一枪最多只能射死
假设下文中所有的
不难求得小鸟数为
当
接着考虑飞走了若干只小鸟,如果某条能打死
Code
void solve() {
memset(f, 0, sizeof f);
cin >> n >> k >> m;
for (int i = 2; i < n; i++) f[(n - 1) / i] += phi[i] * 2;
f[n - 1] += 3;
for (int i = 1; i <= m; i++) {
cin >> del[i].x >> del[i].y;
if (!del[i].x) del[i].y = 1;
else if(!del[i].y) del[i].x = 1;
else {
int gcd = __gcd(del[i].x, del[i].y);
del[i].x /= gcd;
del[i].y /= gcd;
}
}
sort(del + 1, del + m + 1, cmp);
int tmp = 0;
for (int i = 1; i <= m; i++) {
tmp++;
if (del[i].x != del[i + 1].x or del[i].y != del[i + 1].y) {
f[(n - 1) / max(del[i].x, del[i].y)]--;
f[(n - 1) / max(del[i].x, del[i].y) - tmp]++;
tmp = 0;
}
}
int ret = 0;
for (int i = n - 1; i; i--) {
if (f[i] >= k) {
ret += i * k;
break;
} else ret += f[i] * i;
k -= f[i];
}
cout << ret << "\n";
}T2
题意
给出一个长度为
分析
明显向右扩展一个容易,所以采用回滚莫队。
并查集不好回滚,所以不使用。
考虑维护
Code
namespace MoDui {
int block, belong[N], tmp;
int L[N], R[N], recnt;
bool vis[N];
struct REPLACE {
int p, l, r, vis;
} re[N];
void init_block() {
block = sqrt(n);
for (int i = 1; i <= n; i++) belong[i] = (i - 1) / block + 1;
}
bool cmp(QUESTION x, QUESTION y) {
return belong[x.l] != belong[y.l] ? belong[x.l] < belong[y.l] : x.r < y.r;
}
void addre(int x) {
re[++recnt] = {x, L[x], R[x], vis[x]};
vis[x] = true;
if (vis[x - 1]) {
re[++recnt] = {L[x - 1], L[L[x - 1]], R[L[x - 1]], vis[L[x - 1]]};
L[x] = L[x - 1];
R[L[x]] = x;
}
if (vis[x + 1]) {
re[++recnt] = {R[x + 1], L[R[x + 1]], R[R[x + 1]], vis[R[x + 1]]};
L[R[x + 1]] = L[x];
R[L[x]] = R[x + 1];
R[x] = R[x + 1];
}
tmp = max(tmp, R[x] - L[x] + 1);
}
void add(int x) {
vis[x] = true;
if (vis[x - 1]) {
L[x] = L[x - 1];
R[L[x]] = x;
}
if (vis[x + 1]) {
L[R[x + 1]] = L[x];
R[L[x]] = R[x + 1];
R[x] = R[x + 1];
}
tmp = max(tmp, R[x] - L[x] + 1);
}
void solve() {
sort(q + 1, q + m + 1, cmp);
for (int i = 1; i <= n; i++)
vis[a[i]] = 0, L[a[i]] = R[a[i]] = a[i];
int l = 1, r = 0;
for (int i = 1; i <= m; i++) {
if (q[i].l >= l) {
tmp = 0;
for (int j = 1; j <= n; j++) vis[a[j]] = 0, L[a[j]] = R[a[j]] = a[j];
r = belong[q[i].l] * block;
l = r + 1;
tmp = 1;
}
if (belong[q[i].l] == belong[q[i].r]) {
int last = tmp;
for (int j = q[i].l; j <= q[i].r; j++) add(a[j]);
ans[q[i].id] = tmp;
for (int j = q[i].l; j <= q[i].r; j++) vis[a[j]] = 0, L[a[j]] = R[a[j]] = a[j];
tmp = last;
continue;
}
while (r < q[i].r) add(a[++r]);
int last = tmp;
for (int j = q[i].l; j < l; j++) addre(a[j]);
ans[q[i].id] = tmp;
for (int j = recnt; j; j--) {
int p = re[j].p;
L[p] = re[j].l;
R[p] = re[j].r;
vis[p] = re[j].vis;
}
recnt = 0;
tmp = last;
}
}
}
using namespace MoDui;T3
题意
一个国家有
分析
求树上点对数目问题,明显点分治。
首先要判断这条路径是否合法。如果一条路径
先考虑
再考虑
怎么统计答案呢?记录下来
Code
namespace PDC {
int sz[N], mx[N], rt, vs[N], dis[N];
int q1[N], p1, q2[N], p2, m1[N], n1, m2[N], n2;
bool vis[N];
void getrt(int u, int fa, int nodecnt) {
sz[u] = 1;
mx[u] = 0;
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (v == fa or vis[v]) continue;
getrt(v, u, nodecnt);
sz[u] += sz[v];
mx[u] = max(mx[u], sz[v]);
}
mx[u] = max(mx[u], nodecnt - sz[u]);
if (mx[u] < mx[rt]) rt = u;
}
void getdis(int u, int fa, int maxx, int minn) {
if (vs[u] - dis[u] >= maxx) m1[++n1] = vs[u] - dis[u];
m2[++n2] = minn;
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (v == fa or vis[v]) continue;
vs[v] = vs[u] + a[v];
dis[v] = dis[u] + edge[i].w;
getdis(v, u, max(maxx, vs[u] - dis[u]), min(minn, vs[u] - dis[v]));
}
}
void calc(int u) {
int l;
p1 = p2 = 0;
vs[u] = a[u];
dis[u] = 0;
for (int i = head[u]; i; i = edge[i].next) {
int v = edge[i].v;
if (vis[v]) continue;
n1 = n2 = 0;
vs[v] = vs[u] + a[v];
dis[v] = edge[i].w;
getdis(v, u, vs[u] - dis[u], vs[u] - dis[v]);
sort(m1 + 1, m1 + n1 + 1);
sort(m2 + 1, m2 + n2 + 1);
l = 1;
for (int i = n2; i; i--) {
while (l <= n1 and m1[l] + m2[i] - a[u] < 0) l++;
ans -= n1 - l + 1;
}
for (int i = 1; i <= n1; i++) q1[++p1] = m1[i];
for (int i = 1; i <= n2; i++) q2[++p2] = m2[i];
}
ans += p1;
sort(q1 + 1, q1 + p1 + 1);
sort(q2 + 1, q2 + p2 + 1);
l = 1;
for (int i = p2; i; i--) {
if (q2[i] >= 0) ans++;
while (l <= p1 and q1[l] + q2[i] - a[u] < 0) l++;
ans += p1 - l + 1;
}
}
void solve(int u, int nodecnt) {
mx[rt = 0] = oo;
getrt(u, 0, nodecnt);
getrt(rt, 0, nodecnt);
vis[rt] = 1;
calc(rt);
for (int i = head[rt]; i; i = edge[i].next) {
int v = edge[i].v;
if (vis[v]) continue;
solve(v, sz[v]);
}
}
}
using namespace PDC;