大厨砍树

题意:给你一棵树,第二天起每天随机砍一条边。问每一天森林的期望权值。权值为每个连通块的点数平方和。

解:先把平方拆了。发现就是点对数量 * 2,但是两个点相同的时候不 * 2,就是有序点对的数量。

然后可以求树上路径,点分治 + fft。

然后考虑我们要如何计算答案。第i天有C(n - 1, i - 1)种方案。长度为Q的路径仍然存在的方案数为C(n - 1 - Q, i - 1)

然后把这个组合数拆开,只和n,i有关的都提出来,剩下的是个卷积式子。注意卷积里面一定有一个东西的下标与两项都有关。

然后再fft一次就好了。

卡常新技巧:预处理单位根。

  1 /**
  2  * There is no end though there is a start in space. ---Infinity.
  3  * It has own power, it ruins, and it goes though there is a start also in the star. ---Finite.
  4  * Only the person who was wisdom can read the most foolish one from the history.
  5  * The fish that lives in the sea doesn't know the world in the land.
  6  * It also ruins and goes if they have wisdom.
  7  * It is funnier that man exceeds the speed of light than fish start living in the land.
  8  * It can be said that this is an final ultimatum from the god to the people who can fight.
  9  *
 10  * Steins;Gate
 11  */
 12 
 13 /**
 14  * by huyufeifei
 15  */
 16 
 17 #include <bits/stdc++.h>
 18 
 19 #define forson(x, i) for(register int i(*(e + x)); i; i = edge[i].nex)
 20 
 21 const int N = 500010, MO = 998244353, INF = 0x3f3f3f3f;
 22 
 23 inline char gc() {
 24     static char buf[N], *p1(buf), *p2(buf);
 25     if(p1 == p2) {
 26         p2 = (p1 = buf) + fread(buf, 1, N, stdin);
 27     }
 28     return p1 == p2 ? EOF : *p1++;
 29 }
 30 
 31 inline void read(int &x) {
 32     x = 0;
 33     register char c = gc();
 34     while(c < '0' || c > '9') c = gc();
 35     while(c >= '0' && c <= '9') {
 36         x = x * 10 + c - 48;
 37         c = gc();
 38     }
 39     return;
 40 }
 41 
 42 struct Edge {
 43     int nex, v;
 44     bool del;
 45 }edge[N << 1]; int tp = 0;
 46 
 47 int e[N], n, F[N], Time, vis[N], r[N << 2], bin[N], Ans[N], G[N];
 48 int fac[N], inv[N], invn[N], A[N << 2], B[N << 2], d[N], siz[N];
 49 int _n, root, small;
 50 bool del[N];
 51 int W[20][N << 2];
 52 
 53 inline void prework(int n) {
 54     static int R = 0;
 55     if(R == n) return;
 56     R = n;
 57     int lm(1);
 58     while((1 << lm) < n) lm++;
 59     for(register int i(0); i < n; i++) {
 60         *(r + i) = (r[i >> 1] >> 1) | ((i & 1) << (lm - 1));
 61     }
 62     return;
 63 }
 64 
 65 inline int C(int n, int m) {
 66     return 1ll * (*(fac + n)) * invn[m] % MO * invn[n - m] % MO;
 67 }
 68 
 69 inline int qpow(int a, int b) {
 70     int ans(1);
 71     while(b) {
 72         if(b & 1) ans = 1ll * ans * a % MO;
 73         a = 1ll * a * a % MO;
 74         b = b >> 1;
 75     }
 76     return ans;
 77 }
 78 
 79 inline void Add(int &a, const int &b) {
 80     a += b % MO;
 81     while(a >= MO) a -= MO;
 82     while(a < 0) a += MO;
 83     return;
 84 }
 85 
 86 #define add(x, y) tp++; edge[tp].v = y; edge[tp].nex = e[x]; e[x] = tp
 87 
 88 /*inline void add(int x, int y) {
 89     tp++;
 90     edge[tp].v = y;
 91     edge[tp].nex = e[x];
 92     e[x] = tp;
 93     return;
 94 }*/
 95 
 96 inline void preworkW() {
 97     for(int len(1), lm(1); lm < 20; len <<= 1, lm++) {
 98         int Wn = qpow(3, (MO - 1) / (len << 1));
 99         W[lm][0] = 1;
100         //printf("W %d 0 = 1  Wn = %d \n", lm, Wn);
101         for(int j = 1; j <= len * 2; j++) {
102             W[lm][j] = 1ll * W[lm][j - 1] * Wn % MO;
103         }
104         //printf("W[lm][len * 2] = %d \n", W[lm][len * 2]);
105     }
106     return;
107 }
108 
109 inline void NTT(int *a, int n, int f) {
110     prework(n);
111     for(register int i(0); i < n; i++) {
112         if(i < *(r + i)) std::swap(a[i], a[r[i]]);
113     }
114     for(register int len(1), lm(1); len < n; len <<= 1, lm++) {
115         int Wn = qpow(3, (MO - 1) / (len << 1));
116         if(f == -1) Wn = qpow(Wn, MO - 2);
117         for(register int i(0); i < n; i += (len << 1)) {
118             int w2(1);
119             for(register int j(0), p(f == 1 ? 0 : len * 2); j < len; j++, p += f) {
120                 int w = W[lm][p];
121                 //if(w != w2) printf("ERR : len = %d lm = %d j = %d w = %d w2 = %d \n", len, lm, j, w, w2);
122                 int t = 1ll * a[i + len + j] * w % MO;
123                 a[i + len + j] = (a[i + j] - t) % MO;
124                 a[i + j] = (a[i + j] + t) % MO;
125                 w2 = 1ll * w2 * Wn % MO;
126             }
127         }
128     }
129     if(f == -1) {
130         int inv = qpow(n, MO - 2);
131         for(register int i(0); i < n; i++) {
132             a[i] = 1ll * (*(a + i)) * inv % MO;
133         }
134     }
135     return;
136 }
137 
138 inline void cal(int n, int f) {
139     int len = 1;
140     n++;
141     while(len < n * 2) len <<= 1;
142     memcpy(A, bin, n * sizeof(int));
143     memset(A + n, 0, (len - n) * sizeof(int));
144     NTT(A, len, 1);
145     for(register int i(0); i < len; i++) {
146         *(A + i) = 1ll * (*(A + i)) * (*(A + i)) % MO;
147     }
148     NTT(A, len, -1);
149     for(register int i(0); i < len; i++) {
150         (*(Ans + i) += f * (*(A + i))) %= MO;
151     }
152     return;
153 }
154 
155 void getroot(int x, int f, int flag) {
156     if(flag) {
157         (*(bin + (*(d + x))))++;
158     }
159     *(siz + x) = 1;
160     int large(0);
161     forson(x, i) {
162         int y = edge[i].v;
163         if(y == f || (*(del + y))) continue;
164         getroot(y, x, flag);
165         *(siz + x) += *(siz + y);
166         large = std::max(large, *(siz + y));
167     }
168     large = std::max(large, _n - (*(siz + x)));
169     if(large < small) {
170         small = large;
171         root = x;
172     }
173     return;
174 }
175 
176 void DFS_1(int x, int f) {
177     *(d + x) = *(d + f) + 1;
178     (*(bin + (*(d + x))))++;
179     *(siz + x) = 1;
180     forson(x, i) {
181         int y = edge[i].v;
182         if(y == f || (*(del + y))) {
183             continue;
184         }
185         DFS_1(y, x);
186         *(siz + x) += *(siz + y);
187     }
188     return;
189 }
190 
191 //int Cnt;
192 
193 void poi_div(int x, int f) {
194 
195     // printf("x = %d _n = %d last_n = %d f = %d \n", x, _n, last_n, f);
196     //printf("x = %d  Cnt = %d \n", x, ++Cnt);
197 
198     if(f) memset(bin, 0, (_n + 1) * sizeof(int));
199     small = INF;
200     getroot(x, 0, f);
201     if(f) cal(_n, -1);
202     x = root;
203 
204     //printf("root = %d \n", root);
205 
206     memset(bin, 0, (_n + 1) * sizeof(int));
207     //printf("gast 0  \n");
208     DFS_1(x, 0);
209     //printf("gast 1  \n");
210     cal(_n, 1);
211 
212     *(del + x) = 1;
213     memset(bin, 0, (_n + 1) * sizeof(int));
214     forson(x, i) {
215         int y = edge[i].v;
216         if(del[y]) continue;
217         _n = *(siz + y);
218         poi_div(y, 1);
219     }
220     return;
221 }
222 
223 int main() {
224 
225     *d = -1;
226     read(n);
227 
228     preworkW();
229 
230     *inv = *invn = *fac = 1;
231     *(inv + 1) = *(invn + 1) = *(fac + 1) = 1;
232     for(register int i(2); i <= n; i++) {
233         *(fac + i) = 1ll * (*(fac + i - 1)) * i % MO;
234         *(inv + i) = 1ll * (*(inv + MO % i)) * (MO - MO / i) % MO;
235         *(invn + i) = 1ll * (*(invn + i - 1)) * (*(inv + i)) % MO;
236     }
237 
238     for(register int i(1), x, y; i < n; i++) {
239         read(x); read(y);
240         add(x, y); add(y, x);
241     }
242 
243     _n = n;
244     poi_div(1, 0);
245 
246     for(register int i(0); i < n; i++) {
247         //printf("%d ", (Ans[i] + MO) % MO);
248         *(F + i) = 1ll * (*(Ans + i)) * (*(fac + n - i - 1)) % MO;
249         *(G + i) = *(invn + i);
250     }
251 
252     int len(1);
253     while(len < (n << 1)) len <<= 1;
254     memcpy(A, F, n * sizeof(int));
255     memcpy(B, G, n * sizeof(int));
256     memset(A + n, 0, (len - n) * sizeof(int));
257     memset(B + n, 0, (len - n) * sizeof(int));
258     NTT(A, len, 1); NTT(B, len, 1);
259     for(register int i(0); i < len; i++) {
260         *(Ans + i) = 1ll * (*(A + i)) * (*(B + i)) % MO;
261     }
262     NTT(Ans, len, -1);
263 
264     //printf("OVER \n");
265 
266     for(register int i(1); i <= n; i++) {
267         int ans = 1ll * (*(Ans + n - i)) * (*(invn + n - 1)) % MO * (*(fac + n - i)) % MO;
268         printf("%d\n", (ans + MO) % MO);
269     }
270 
271     return 0;
272 }
AC代码

 

posted @ 2019-04-01 15:26  huyufeifei  阅读(179)  评论(0)    收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜