bzoj 4770 圖樣 - 機率與指望 - 動態規劃

題目傳送門php

  傳送門Iios

  傳送門IIspa

題目大意.net

  有一個$n$個點的徹底圖,每一個點的權值是$[0, 2^{m})$中的隨機整數,兩點間的邊的權值是兩點點權的異或和,問它的最小異或生成樹的邊權和的指望。code

  考慮求最大異或生成樹的分治作法,每次按最高位分紅$V_0,V_1$兩個集合(若是不行,那麼這一層就無論)。blog

  而後再中間選一條最小邊鏈接兩個集合。兩個集合分別再分治下去。get

  如今咱們但願求到中間這條最小邊的邊權的指望。string

  直接求很差求,考慮換個方式統計。it

  設$h_{n,m,bit,lim}$表示在第$bit + 1$位將圖分紅$X,Y$兩個集合,其中$|X| = n, |Y| = m$,兩個集合間的全部邊的邊權都大於等於$lim$的方案數(或機率)。io

  轉移的時候討論一下

  • $lim$在第$bit$位爲0
    • 若是$X,Y$中的點在$bit$位,一個集合中全爲0,另外一個集合中全爲1,那麼剩下的位能夠任意填。
    • 不然枚舉$X,Y$中分別有多少個點在第$bit$位爲1,而後將集合又分爲$X_0, X_1, Y_0, Y_1$,顯然最小邊連在$X_0, Y_0$之間或者$X_1,Y_1$之間,這是一個子問題,能夠經過這個子問題的答案轉移,再乘上組合數。
  • $lim$在第$bit$位爲1
    • 此時$X,Y$中的點在$bit$位必定知足一個集合中全爲0,另外一個集合中全爲1,直接經過它轉移。

  統計指望或每種狀況的邊權和的時候作一個和就求出來了。

  設$f_{i, j}$表示有一個$i$個點的徹底圖,每一個點的權值是$[0, 2^{j})$中的隨機整數時的全部方案的答案和。

  顯然能經過枚舉$X_1$集合的大小來轉移。

  複雜度使人絕望(聽說常數小就能卡過去)。可是$n,m$都比較小,打個表交上去就過了。

Code

  1 #include <iostream>
  2 #include <cstdlib>
  3 #include <cstring>
  4 #include <cstdio>
  5 using namespace std;
  6 typedef bool boolean;
  7 
  8 const int N = 55, M = 9, S = 1 << M;
  9 const int Mod = 258280327;
 10 
 11 int add(int a, int b) {
 12     return ((a += b) >= Mod) ? (a - Mod) : (a);
 13 }
 14 
 15 int sub(int a, int b) {
 16     return ((a -= b) < 0) ? (a + Mod) : (a);
 17 }
 18 
 19 int mul(int a, int b) {
 20     return a * 1ll * b % Mod;
 21 }
 22 
 23 int qpow(int a, int p) {
 24     int pa = a, rt = 1;
 25     for ( ; p; p >>= 1, pa = mul(pa, pa))
 26         if (p & 1)
 27             rt = mul(rt, pa);
 28     return rt;
 29 }
 30 
 31 int inv(int a, int n) {
 32     return qpow(a, n - 2);
 33 }
 34 
 35 int n, m;
 36 int f[N][N];
 37 int comb[N][N];
 38 int pow2[N * M];
 39 int h[N][N][M][S];
 40 
 41 inline void init() {
 42     scanf("%d%d", &n, &m);
 43     comb[0][0] = 1;
 44     for (int i = 1; i <= n; i++) {
 45         comb[i][0] = comb[i][i] = 1;
 46         for (int j = 1; j < i; j++)
 47             comb[i][j] = add(comb[i - 1][j - 1], comb[i - 1][j]);
 48     }
 49     pow2[0] = 1;
 50     for (int i = 1; i <= (n + 1) * (m + 1) + 1; i++)
 51         pow2[i] = add(pow2[i - 1], pow2[i - 1]);
 52 }
 53 
 54 int dp(int n, int m, int bit, int lim) {
 55     if (!bit)
 56         return !lim;
 57     if (!n || !m)
 58         return pow2[(n + m) * bit];
 59     int& rt = h[n][m][bit][lim];
 60     if (~rt)
 61         return rt;
 62     if ((lim >> (bit - 1)) & 1) {
 63         rt = dp(n, m, bit - 1, lim ^ (1 << (bit - 1)));
 64         rt = add(rt, rt);
 65     } else { 
 66         rt = pow2[(n + m) * (bit - 1) + 1];
 67         for (int x = 0; x <= n; x++)
 68             for (int y = 0; y <= m; y++) {
 69                 if ((!x && y == m) || (!y && x == n))
 70                     continue;
 71                 int a = dp(x, y, bit - 1, lim);
 72                 int b = dp(n - x, m - y, bit - 1, lim);
 73                 rt = add(rt, mul(mul(a, b), mul(comb[n][x], comb[m][y])));
 74             }
 75     }
 76     return rt;
 77 }
 78 
 79 int g(int n, int m, int bit) {
 80     int rt = 0;
 81     for (int i = 1; i < pow2[bit]; i++)
 82         rt = add(rt, dp(n, m, bit, i));
 83 //    cerr << n << " " << m << " " << rt << " " << bit << '\n';
 84     return rt;
 85 }
 86 
 87 inline void solve() {
 88     memset(h, -1, sizeof(h));
 89     for (int i = 1; i <= n; i++)
 90         for (int j = 1; j <= m; j++) {
 91             int& val = f[i][j];
 92             val = add(f[i][j - 1], f[i][j - 1]);
 93             for (int cnt = 1, tmp; cnt < i; cnt++) {
 94                 tmp = mul(f[cnt][j - 1], pow2[(i - cnt) * (j - 1)]);
 95                 tmp = add(tmp, mul(f[i - cnt][j - 1], pow2[cnt * (j - 1)]));
 96                 tmp = add(tmp, g(cnt, i - cnt, j - 1));
 97                 tmp = add(tmp, pow2[(i + 1) * (j - 1)]);
 98 //                printf("tmp %d %d  %d= %d\n", i, j, cnt, tmp);
 99                 val = add(val, mul(tmp, comb[i][cnt]));
100             }
101 //            printf("f[%d][%d] = %d\n", i, j, f[i][j]);
102         }
103     for (int i = 1; i <= n; i++) {
104         for (int j = 0; j <= m; j++) {
105             printf("\tf[%d][%d] = %d;\n", i, j, mul(f[i][j], inv(pow2[i * j], Mod)));
106         }
107     }
108 }
109 
110 int main() {
111     freopen("young.txt", "w", stdout);
112     init();
113     solve();
114     return 0;
115 }
相關文章
相關標籤/搜索