• 大厨砍树


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

    解:先把平方拆了。发现就是点对数量 * 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 }
    AC代码
  • 相关阅读:
    nioSocket
    Socket
    常见协议和标准
    Object类clone方法
    java中的运算符
    java中方法的定义
    Spring中实现定时调度
    Spring中对资源的读取支持
    HashMap的实现原理
    固定Realm 与配置数据库连接实现登录验证
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10636668.html
Copyright © 2020-2023  润新知