zoukankan      html  css  js  c++  java
  • 大厨砍树

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

    解:先把平方拆了。发现就是点对数量 * 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代码
  • 相关阅读:
    java操作生成jar包 和写入jar包
    jboss配置jndi连接池
    windows 域的LDAP查询相关举例
    LDAP error Code 及解决方法
    HDU 6417
    CF1299D Around the World
    codechef Chef and The Colored Grid
    Educational Codeforces Round 82 (Rated for Div. 2)
    CF1237F Balanced Domino Placements
    CF1254E Send Tree to Charlie
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10636668.html
Copyright © 2011-2022 走看看