题意:给你一棵树,第二天起每天随机砍一条边。问每一天森林的期望权值。权值为每个连通块的点数平方和。
解:先把平方拆了。发现就是点对数量 * 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 ", 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 ", 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 ", 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 ", x, _n, last_n, f); 196 //printf("x = %d Cnt = %d ", 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 ", root); 205 206 memset(bin, 0, (_n + 1) * sizeof(int)); 207 //printf("gast 0 "); 208 DFS_1(x, 0); 209 //printf("gast 1 "); 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 "); 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 ", (ans + MO) % MO); 269 } 270 271 return 0; 272 }