「十二省联考 2019」希望
Posted fexuile
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了「十二省联考 2019」希望相关的知识,希望对你有一定的参考价值。
「十二省联考 2019」希望
下面全是口胡
传送门
题解
暴力
首先考虑一个暴力的(dp),设(f_{u,i})表示以(u)为根的子树,最长的长度不超过(j)的连通块个数,(g_{u,i})表示(u)子树外的长度不超过(i)的连通块个数.这个时候有:
[f_{u,i}=prod_{vin son_u}(f_{v,i-1}+1)
g_{u,i}=g_{fa,i-1}prod_{v in son_{fa},v
e u}f_{v,i-2}+1
]
然后答案考虑容斥,如果你对于每一个(u)计算(f_{u,L}*g_{u,L}),会算重复一些连通块,那么根据如下事实:
连通块的交还是一个连通块,我们可以想到一个容斥,即:点的贡献-边的贡献就是答案.
所以答案为:((f_{u,L}*g_{u,L})^k-(f_{u,L-1}*(g_{u,L}-1))^k)
优化
接下来考虑怎么优化这个求(f)和(g)的过程.
把(f_{u,i} ightarrow f_{u,i}+1),那么这就是一个长链剖分转移(dp),然后打一个全局标记.
但是这个时候不会转移(len_v)以后的数字,这个时候要给全局打一个乘法标记,然后对前面打一个逆元的乘法.
计算(g)你需要考虑暴力计算下,我们可以通过前后缀积计算.
长链剖分下,我们还是可以计算前缀积,后缀积考虑用一个回退数据结构维护即可.
代码
把儿子的代码贴过来
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <list>
#include <algorithm>
#define ll long long
#define Add(a, b) (a + b + Mod) % Mod
#define Mul(a, b) 1ll * a *b % Mod
#define Assign(x) (f[x] = pf, pf += T.len[x] + 2, pg += T.len[x] + 2, g[x] = pg - max(L - T.len[x], 0), pg += T.len[x] + 2)
#define Gmin(x, y) (x > (y) && (x = (y)))
using namespace std;
inline int read() {
int sum = 0, f = 1;
char c = getchar();
while (c > ‘9‘ || c < ‘0‘) {
if (c == ‘-‘)
f = -1;
c = getchar();
}
while (c <= ‘9‘ && c >= ‘0‘) {
sum = sum * 10 + c - ‘0‘;
c = getchar();
}
return f * sum;
}
const int N = 1000005;
const int Mod = 998244353;
struct edge {
int to, next;
} e[N << 1];
int n, L, K, ans;
int head[N], cnt;
int _f[N << 4], _g[N << 4], *f[N], *g[N], *pf = _f, *pg = _g;
inline void add(int x, int y) {
e[++cnt] = (edge){ head[x], y };
head[x] = cnt;
}
inline ll fpow(ll a, ll b) {
ll ret = 1;
while (b) {
if (b & 1)
ret = Mul(ret, a);
a = Mul(a, a);
b >>= 1;
}
return ret;
}
struct pre {
int s[N], len[N], u[N], w[N], inv[N];
vector<int> B[N], S[N];
inline void dfs(int x, int fa) {
inv[x] = 1;
for (int i = head[x]; i; i = e[i].to) {
int k = e[i].next;
if (k == fa)
continue;
dfs(k, x);
if (len[k] > len[s[x]])
s[x] = k;
inv[x] = Mul(inv[x], inv[k]);
}
len[x] = len[s[x]] + 1;
inv[x] = Add(inv[x], 1);
if (!s[x])
return;
int maxn = 0;
for (int i = head[x]; i; i = e[i].to) {
int k = e[i].next;
if (k == fa || k == s[x])
continue;
B[len[k]].push_back(k);
maxn = max(maxn, len[k]);
}
for (int i = maxn; i >= 0; i--) {
for (int j = 0, mx = B[i].size(); j < mx; j++) S[x].push_back(B[i][j]);
B[i].clear();
}
}
inline void init() {
int tot = 0;
len[0] = -1;
dfs(1, 0);
w[0] = 1;
for (int i = 1; i <= n; i++)
if (inv[i])
u[++tot] = i, w[tot] = Mul(w[tot - 1], inv[i]);
w[tot] = fpow(w[tot], Mod - 2);
for (int i = tot; i; i--) {
int x = inv[u[i]];
inv[u[i]] = Mul(w[i], w[i - 1]);
w[i - 1] = Mul(w[i], x);
}
}
} T;
struct back {
struct pr {
int *w, v;
};
list<pr> t;
inline void ins(int &x) { t.push_back((pr){ &x, x }); }
inline void reset() {
while (!t.empty()) *(t.back().w) = t.back().v, t.pop_back();
}
} S[N];
struct fff {
int mul[N], imul[N], add[N], lim[N], zero[N];
inline int gv(int x, int p) {
return Gmin(p, T.len[x]), Add(1LL * mul[x] * (p < lim[x] ? f[x][p] : zero[x]) % Mod, add[x]);
}
inline int giv(int x, int v) { return Mul(imul[x], Add(v, -add[x])); }
inline void dfs(int x, int fa) {
int ls = T.s[x];
if (!ls) {
lim[x] = mul[x] = imul[x] = add[x] = 1;
// add[x]=Add(add[x],1);//return ;
goto End;
}
f[T.s[x]] = f[x] + 1;
dfs(T.s[x], x);
mul[x] = mul[T.s[x]];
imul[x] = imul[T.s[x]];
add[x] = add[T.s[x]];
zero[x] = zero[T.s[x]];
lim[x] = lim[T.s[x]] + 1;
f[x][0] = giv(x, 1);
for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
int k = T.S[x][i];
ls = k;
Assign(k);
dfs(k, x);
for (int j = 0; j <= T.len[k] + 1; j++) {
if (lim[x] == j)
S[k].ins(lim[x]), S[k].ins(f[x][j]), f[x][lim[x]++] = zero[x];
S[k].ins(f[x][j]);
f[x][j] = giv(x, Mul(gv(x, j), (j ? gv(k, j - 1) : 1)));
}
if (T.len[x] <= T.len[k] + 1)
continue;
int w = gv(k, T.len[k]);
if (!w)
S[k].ins(lim[x]), S[k].ins(zero[x]), lim[x] = T.len[k] + 1, zero[x] = giv(x, 0);
else {
S[k].ins(mul[x]);
S[k].ins(imul[x]);
S[k].ins(add[x]);
mul[x] = Mul(mul[x], w);
add[x] = Mul(add[x], w);
imul[x] = Mul(imul[x], T.inv[k]);
for (int j = 0; j <= T.len[k] + 1; j++)
S[k].ins(f[x][j]), f[x][j] = giv(x, Mul(gv(x, j), T.inv[k]));
}
}
S[ls].ins(add[x]);
End:
add[x] = Add(add[x], 1);
}
inline void solve() {
Assign(1);
dfs(1, 0);
}
} F;
struct ggg {
int mul[N], imul[N], zero[N], add[N], lim[N], u[N];
// inline int GV(CI x,CI p) {return XSum(1LL*Mul[x]*(p<Lim[x]?g[x][p]:Zero[x])%X,Add[x]);}//与之前类似
inline int gv(int x, int p) { return Add(Mul(mul[x], (p < lim[x] ? g[x][p] : zero[x])), add[x]); }
inline int giv(int x, int v) { return Mul(imul[x], Add(v, -add[x])); }
inline void dfs(int x, int fa) {
// for(int i=0;i<=T.len[x];i++) printf("g[%d][%d]=%d
",x,i,g[x][i]);
u[0] = 1;
reverse(T.S[x].begin(), T.S[x].end());
ans = Add(ans, fpow(Mul(Add(F.gv(x, L), -1), gv(x, L)), K));
if (fa)
ans = Add(ans, -fpow(Mul(Add(F.gv(x, L - 1), -1), Add(gv(x, L), -1)), K));
if (!T.s[x])
return;
int prod = 1, Mx = 0;
for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
int k = T.S[x][i];
S[k].reset();
lim[k] = L + 1;
mul[k] = imul[k] = 1;
for (int j = max(L - T.len[k], 0); j <= L; j++) {
g[k][j] = Add(Mul((j ? gv(x, j - 1) : 0),
(j > 1 ? Mul(F.gv(x, j - 1), (j - 2 > Mx ? prod : u[j - 2])) : 1)),
1);
}
for (int j = 0; j <= T.len[k]; j++) u[j] = Mul((j > Mx ? prod : u[j]), F.gv(k, j));
prod = Mul(prod, F.gv(k, Mx = T.len[k]));
}
int ls = T.s[x];
g[T.s[x]] = g[x] - 1;
mul[T.s[x]] = mul[x];
imul[T.s[x]] = imul[x];
add[T.s[x]] = add[x];
zero[T.s[x]] = zero[x];
lim[T.s[x]] = lim[x] + 1;
if (L <= T.len[T.s[x]])
g[T.s[x]][0] = giv(T.s[x], 0);
for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
int k = T.S[x][i];
for (int j = max(0, L - T.len[ls]); j <= min(L, T.len[k] + 2); j++) {
if (lim[ls] == j)
g[ls][lim[ls]++] = zero[ls];
g[ls][j] = giv(ls, Mul(gv(ls, j), (j > 1 ? F.gv(k, j - 2) : 1)));
}
if (L <= T.len[k] + 2)
continue;
int w = F.gv(k, T.len[k]);
if (!w)
lim[ls] = T.len[k] + 2, zero[ls] = giv(ls, 0);
else {
mul[ls] = Mul(mul[ls], w);
add[ls] = Mul(add[ls], w);
imul[ls] = Mul(imul[ls], T.inv[k]);
for (int j = max(0, L - T.len[ls]); j <= min(L, T.len[k] + 2); j++) {
g[ls][j] = giv(ls, Mul(gv(ls, j), T.inv[k]));
}
}
}
add[T.s[x]] = Add(add[T.s[x]], 1);
dfs(T.s[x], x);
for (int i = 0, mx = T.S[x].size(); i < mx; i++) {
int k = T.S[x][i];
if (k != fa)
dfs(k, x);
}
}
inline void solve() {
mul[1] = add[1] = imul[1] = 1;
lim[1] = L + 1;
dfs(1, 0);
}
} G;
signed main() {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
n = read();
L = read();
K = read();
for (int i = 1; i ^ n; i++) {
int x = read(), y = read();
add(x, y);
add(y, x);
}
T.init();
F.solve();
G.solve();
printf("%d
", ans);
return 0;
}
以上是关于「十二省联考 2019」希望的主要内容,如果未能解决你的问题,请参考以下文章