传送门:
https://floj.tech/contest/449
题解:
注意到每次只会把一段往前copy,那么一个点每次都会只会向前走,假设现在x∈[yi,yi+1),hi>0,那么x一次向左会跳yi-hi的距离,直到跳到yi左边。
这个可以直接除一下来得到跳出这段后的位置,倒着扫,x最终会定在一个点上。
如果两个点最终汇聚在一个点上,它们就是一样的。
时间复杂度 O ( ( a + q ) b ) O((a+q)b) O((a+q)b)
题解:
首先对于z考虑[l…r]包含他的条件是什么?
显然就是两个不同的子树里都有[l…r]的点。
考虑一次枚举z的子树里的点,假设现在枚举到了y子树里的x点,把x点放到y子树之前的所有子树的点中,显然取相邻的两个点是最优的(左一个,右一个),这样会有若干对(a,b)
用启发式合并就可以做到(a,b)的总对数是O(n log n),用set维护相邻,这一部分复杂度是O(n log^2 n)
若有一对(a,b)满足l<=a&&r>=n,那么[l…r]在z上就是可行的。
但是我们不可能枚举每个询问,可能是要把(a,b)整体做。
把所有(a,b)按a排序,显然b也要升序,不然就去掉,相当于做个单调栈。
然后做出若干个(ai,a_{i+1}],b_{i+1},这样只用找到l对应的那一段,然后判断r>=b_{i+1},而不是之前的存在性问题。
二维偏序的话扫描线+树状数组。
复杂度大概为 O ( n l o g 2 n + 2 n l o g n l o g ( n l o g n ) ) O(n log^2 n+2 n log n log (n log n)) O(nlog2n+2nlognlog(nlogn))
题解:
我们很容易想到一种计算方法:
枚举二分图左边的点数x(0<=x<=n),这个贡献就是
C
n
x
∗
3
x
(
n
−
x
)
C_{n}^x*3^{x(n-x)}
Cnx∗3x(n−x)。
这显然会有重复,一种具体方案重复的次数是 2 联 通 块 个 数 2^{联通块个数} 2联通块个数
于是想到一个dp:
设
f
(
i
,
j
)
f(i,j)
f(i,j)表示i个点,j个连通块的贡献和。
g
(
n
)
g(n)
g(n)就表示之前那种计算方法的贡献。
结合做过的城市规划,不难列出转移:
f
(
i
,
j
)
(
j
>
1
)
f(i,j)(j>1)
f(i,j)(j>1)
=
∑
x
=
1
i
−
1
C
i
−
1
x
−
1
∗
f
x
,
1
∗
f
i
−
x
,
j
−
1
=\sum_{x=1}^{i-1}C_{i-1}^{x-1}*f_{x,1}*f{i-x,j-1}
=∑x=1i−1Ci−1x−1∗fx,1∗fi−x,j−1
f ( i , 1 ) = ( g ( i ) − ∑ x = 2 i f i , j ∗ 2 j ) / 2 f(i,1)=(g(i)-\sum_{x=2}^{i}f_{i,j}*2^{j})/2 f(i,1)=(g(i)−∑x=2ifi,j∗2j)/2
求出 f i , 1 f_{i,1} fi,1之后就可以算答案了,设 s ( n ) s(n) s(n)表示n个点时的答案。
s ( n ) = ∑ x = 1 n C n − 1 x − 1 ∗ f ( x , 1 ) ∗ s ( n − x ) s(n)=\sum_{x=1}^n C_{n-1}^{x-1}*f(x,1)*s(n-x) s(n)=∑x=1nCn−1x−1∗f(x,1)∗s(n−x)
至此得到一个 O ( n 3 ) O(n^3) O(n3)的做法。
发现 f ( i , j ) ( j > 1 ) f(i,j)(j>1) f(i,j)(j>1)的转移是基本一样的,所以可以去掉后一维,设 f ( n ) f(n) f(n)直接表示n个点一个联通块的贡献。
f ( n ) = ( g ( n ) − ∑ x = 1 n − 1 C n − 1 x − 1 ∗ f ( x ) ∗ g ( n − x ) ∗ 2 ) / 2 f(n)=(g(n)-\sum_{x=1}^{n-1}C_{n-1}^{x-1}*f(x)*g(n-x)*2)/2 f(n)=(g(n)−∑x=1n−1Cn−1x−1∗f(x)∗g(n−x)∗2)/2
那么复杂度就变成了 O ( n 2 ) O(n^2) O(n2)
显然f和s的转移都可以用分治NTT或多项式求逆优化,复杂度O(n log n)。
最后的瓶颈在于g。
比赛时就卡在了g,很痛苦
这是一个套路,可惜我不知道。
(
(
a
+
b
)
2
−
a
2
−
b
2
)
/
2
=
a
b
((a+b)^2-a^2-b^2)/2=ab
((a+b)2−a2−b2)/2=ab
g
(
n
)
=
∑
x
=
0
n
C
n
x
∗
3
x
(
n
−
x
)
g(n)=\sum_{x=0}^n C_{n}^x*3^{x(n-x)}
g(n)=∑x=0nCnx∗3x(n−x)
=
∑
x
=
0
n
C
n
x
∗
3
(
n
2
−
x
2
−
(
n
−
x
)
2
)
/
2
=\sum_{x=0}^n C_{n}^x*3^{(n^2-x^2-(n-x)^2)/2}
=∑x=0nCnx∗3(n2−x2−(n−x)2)/2
这样就有一个卷积的东西了,不过因为mod 998244353意义下没有 3 \sqrt 3 3,所以要分奇偶讨论。
最后的结果是做两次NTT就行了。
总复杂度O(n log n),不过多项式求逆我不是很熟,所以用了cdq分治NTT。
Code:
T1:
#include<map>
#include<cstdio>
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
using namespace std;
const int N = 1005;
int n, a, b, q, x;
struct nod {
int x; char c;
} c[N];
int y[N], h[N];
int la(int x) {
fd(i, b, 1)
if(x >= y[i] && x < y[i + 1]) {
if(!h[i]) continue;
int z = (x - y[i]) / (y[i] - h[i]);
x -= (z + 1) * (y[i] - h[i]);
}
return x;
}
map<int, int> bz;
int main() {
scanf("%d %d %d %d", &n, &a, &b, &q);
fo(i, 1, a) scanf("%d %c", &c[i].x, &c[i].c);
fo(i, 1, b) scanf("%d %d", &y[i], &h[i]);
y[b + 1] = n + 1;
fo(i, 1, a) bz[la(c[i].x)] = c[i].c;
fo(i, 1, q) {
scanf("%d", &x);
printf("%c", bz[la(x)] ? bz[la(x)] : '?');
}
}
T2:
#include<set>
#include<cstdio>
#include<algorithm>
#define pr printf
#define low(a) ((a) & -(a))
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;
const int N = 3e5 + 5;
int n, m, x, y;
int fi[N], nt[N * 2], to[N * 2], tot;
struct ak {
int l, r, i;
} q[N];
void link(int x, int y) {
nt[++ tot] = fi[x], to[tot] = y, fi[x] = tot;
}
int siz[N], son[N], top[N], dep[N], fa[N];
void dg(int x) {
siz[x] = 1;
dep[x] = dep[fa[x]] + 1;
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x])
fa[to[i]] = x, dg(to[i]),
siz[x] += siz[to[i]],
son[x] = siz[to[i]] > siz[son[x]] ? to[i] : son[x];
}
void dfs(int x) {
if(son[x]) top[son[x]] = top[x], dfs(son[x]);
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x] && to[i] != son[x])
top[to[i]] = to[i], dfs(to[i]);
}
set<int> s;
int d[N];
void bb(int x) {
d[++ d[0]] = x;
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x])
bb(to[i]);
}
struct nod {
int a, b;
nod(int _a = 0, int _b = 0) {a = _a, b = _b;}
} a[N * 60]; int a0;
void gg() {
if(s.size()) {
int mi = *s.begin(), mx = *s.rbegin();
fo(i, 1, d[0]) {
int x = d[i];
if(mi < x) a[++ a0] = nod(*--s.lower_bound(x), x);
if(mx > x) a[++ a0] = nod(x, *s.upper_bound(x));
}
}
fo(i, 1, d[0]) s.insert(d[i]);
}
int cmp(nod a, nod b) {
if(a.a < b.a) return 1;
if(a.a > b.a) return 0;
return a.b > b.b;
}
struct edge {
int fi[N], to[N * 60], nt[N * 60], tot;
bool v[N * 60];
void link(int x, int y, bool z) {
nt[++ tot] = fi[x], to[tot] = y, v[tot] = z, fi[x] = tot;
}
} e;
void ad(int x, int y, int r) {
e.link(x, r, 1); e.link(y + 1, r, 0);
}
void dd(int x) {
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x] && to[i] != son[x])
dd(to[i]);
if(son[x]) dd(son[x]);
a0 = 0;
d[d[0] = 1] = x; gg();
for(int i = fi[x]; i; i = nt[i]) if(to[i] != fa[x] && to[i] != son[x]) {
d[0] = 0; bb(to[i]);
gg();
}
a[++ a0] = nod(x, x);
sort(a + 1, a + a0 + 1, cmp);
int z0 = 0;
fo(i, 1, a0) {
while(z0 > 0 && a[z0].b >= a[i].b) z0 --;
a[++ z0] = a[i];
} a0 = z0;
fo(i, 1, a0) ad(a[i - 1].a + 1, a[i].a, a[i].b);
if(x != son[fa[x]]) s.clear();
}
int f[N];
void add(int x, int y) { while(x <= n) f[x] += y, x += low(x);}
int sum(int x) {
int s = 0;
while(x) s += f[x], x -= low(x);
return s;
}
int cmp2(ak a, ak b) {
return a.l < b.l;
}
int ans[N];
int main() {
scanf("%d %d", &n, &m);
fo(i, 1, n - 1) {
scanf("%d %d", &x, &y);
link(x, y); link(y, x);
}
dg(1); top[1] = 1; dfs(1);
dd(1);
fo(i, 1, m) scanf("%d %d", &q[i].l, &q[i].r), q[i].i = i;
sort(q + 1, q + m + 1, cmp2);
int L = 1;
fo(i, 1, m) {
while(L <= q[i].l) {
for(int j = e.fi[L]; j; j = e.nt[j])
add(e.to[j], e.v[j] ? 1 : -1);
L ++;
}
ans[q[i].i] = sum(q[i].r);
}
fo(i, 1, m) printf("%d\n", ans[i]);
}
T3:
#include<cstdio>
#include<algorithm>
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define fd(i, x, y) for(int i = x; i >= y; i --)
#define ff(i, x, y) for(int i = x; i < y; i ++)
using namespace std;
const ll mo = 998244353;
const int N = 8e5 + 5;
int n, T;
ll a[N], b[N], w[N], tp;
ll ksm(ll x, ll y) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
const ll ni3 = ksm(3, mo - 2);
const ll ni2 = ksm(2, mo - 2);
void Dft(ll *a, int n) {
ff(i, 0, n) {
int p = 0, q = i;
fo(j, 1, tp) p = p * 2 + q % 2, q /= 2;
if(i > p) swap(a[i], a[p]);
}
for(int m = 2; m <= n; m *= 2) {
int h = m / 2;
ff(i, 0, h) {
ll W = w[i * (n / m)];
for(int j = i; j < n; j += m) {
int k = j + h;
ll u = a[j], v = a[k] * W;
a[j] = (u + v) % mo;
a[k] = (u - v) % mo;
}
}
}
}
void fft(ll *a, ll *b, int n) {
ll v = ksm(3, (mo - 1) / n);
w[0] = 1; fo(i, 1, n) w[i] = w[i - 1] * v % mo;
Dft(a, n); Dft(b, n);
ff(i, 0, n) a[i] = a[i] * b[i] % mo;
fo(i, 1, n / 2) swap(w[i], w[n - i]);
Dft(a, n); v = ksm(n, mo - 2);
ff(i, 0, n) a[i] = (a[i] + mo) * v % mo;
}
ll fac[N], nf[N];
ll f[N], g[N], s[N];
void cl() { ff(i, 0, 1 << tp) a[i] = b[i] = 0;}
void dg(int x, int y) {
if(x == y) {
f[x] = (g[x] - 2 * fac[x - 1] * f[x] % mo + mo) * ni2 % mo;
return;
}
int m = (x + y) / 2;
dg(x, m);
tp = 0;
while(1 << ++ tp <= y + m - 2 * x + 1);
cl();
fo(i, 1, m - x + 1) a[i] = f[x + i - 1] * nf[x + i - 2] % mo;
fo(i, 1, y - x) b[i] = g[i] * nf[i] % mo;
fft(a, b, 1 << tp);
fo(i, m + 1, y) f[i] = (f[i] + a[i - x + 1]) % mo;
dg(m + 1, y);
}
void dg2(int x, int y) {
if(x == y) {
if(!x) s[x] ++; else
s[x] = s[x] * fac[x - 1] % mo;
return;
}
int m = (x + y) / 2;
dg2(x, m);
tp = 0;
while(1 << ++ tp <= y + m - 2 * x + 1);
cl();
fo(i, 1, m - x + 1) a[i] = s[x + i - 1] * nf[x + i - 1] % mo;
fo(i, 1, y - x) b[i] = f[i] * nf[i - 1] % mo;
fft(a, b, 1 << tp);
fo(i, m + 1, y) s[i] = (s[i] + a[i - x + 1]) % mo;
dg2(m + 1, y);
}
int q, x;
int main() {
n = 100000;
fac[0] = 1; fo(i, 1, n) fac[i] = fac[i - 1] * i % mo;
nf[n] = ksm(fac[n], mo - 2);
fd(i, n, 1) nf[i - 1] = nf[i] * i % mo;
while(1 << tp ++ <= n);
fo(i, 0, n) if(i & 1) a[i] = b[i] = nf[i] * ksm(ni3, (ll) i * i / 2);
fft(a, b, 1 << tp);
fo(i, 1, n) g[i] = a[i];
cl();
fo(i, 0, n) a[i] = b[i] = nf[i] * ksm(ni3, (ll) i * i / 2);
fft(a, b, 1 << tp);
fo(i, 1, n) g[i] = ((a[i] - g[i] + mo) + g[i] * ni3) % mo * fac[i] % mo * ksm(3, (ll) i * i / 2) % mo;
dg(1, n);
dg2(0, n);
for(scanf("%d", &q); q; q --) scanf("%d", &x), printf("%lld\n", s[x]);
}