• PKUWC 2018 Day 2 简要题解


    *注意:题面请移步至loj查看。

      怎么PKU和THU都编了一些假算法,然后求正确率[汗]。

      之前听说PKUWC 2017考了五道dp,看来是真的。[完蛋.jpg]

      这三道题,2道概率,1道期望,和佬题组成一样。。。

      (我只是把PKUWC 2017在loj后3题做了,是不是全是Day 2就不知道了)

    Problem A 随机算法

    题目大意

      给定一个图。随机一个排列$p_{1}p_2p_3cdots p_n$。假设当前有一个独立集集合$S$,从小到大枚举$i$,尝试将$p_i$加入$S$中。问得到最大独立集的概率。

      每个点有三个状态:被考虑其在独立集中,被考虑且不再独立集中,还未被考虑。

      设$f_S$表示,当独立集状态为$S$的概率。

      每次我们选择独立集中的点的时候,把新增加的不可能在独立集中的点在排列中的位置也考虑了。

      这样一个状态,我们就能表示上面三种点了。

      时间复杂度$O(n2^n)$

    Code

      1 /**
      2  * loj
      3  * Problem#2540
      4  * Accepted
      5  * Time: 623ms
      6  * Memory: 10876k
      7  */
      8 #include <iostream>
      9 #include <cstdlib>
     10 #include <cstdio>
     11 using namespace std;
     12 typedef bool boolean;
     13 
     14 const int Mod = 998244353;
     15 
     16 const int N = 20, S = 1 << N;
     17 
     18 int add(int a, int b) {
     19     return ((a += b) >= Mod) ? (a - Mod) : (a);
     20 }
     21 
     22 int mul(int a, int b) {
     23     return a * 1ll * b % Mod;
     24 }
     25 
     26 void exgcd(int a, int b, int& x, int& y) {
     27     if (!b)
     28         x = 1, y = 0;
     29     else {
     30         exgcd(b, a % b, y, x);
     31         y -= (a / b) * x; 
     32     }
     33 }
     34 
     35 int inv(int a, int n) {
     36     int x, y;
     37     exgcd(a, n, x, y);
     38     return (x < 0) ? (x + n) : (x);
     39 }
     40 
     41 int n, m;
     42 int bit[S];
     43 int g[N], f[S];
     44 boolean indep[S];
     45 int fac[N], _fac[N], adj[S];
     46 
     47 inline void init() {
     48     scanf("%d%d", &n, &m);
     49     for (int i = 0, u, v; i < m; i++) {
     50         scanf("%d%d", &u, &v);
     51         --u, --v;
     52         g[u] |= (1 << v);
     53         g[v] |= (1 << u);
     54     }
     55 }
     56 
     57 int permu(int n, int m) {
     58     if (n < m)
     59         return 0;
     60     return mul(fac[n], _fac[n - m]);
     61 }
     62 
     63 inline void solve() {
     64     int all = 1 << n;
     65     indep[0] = true;
     66     for (int i = 1; i < all; i++)
     67         for (int j = 0; j < n && !indep[i]; j++)
     68             if (((i >> j) & 1) && indep[i ^ (1 << j)] && !(g[j] & i))
     69                 indep[i] = true;
     70     
     71     for (int i = 1; i < all; i++)
     72         bit[i] = bit[i >> 1] + (i & 1);
     73     
     74     int mx = 0;
     75     for (int i = 1; i < all; i++)
     76         if (indep[i] && bit[i] > mx)
     77             mx = bit[i];
     78         
     79     adj[0] = 0;
     80     for (int i = 1; i < all; i++)
     81         for (int j = 0; j < n && !adj[i]; j++)
     82             if ((i >> j) & 1)
     83                 adj[i] = adj[i ^ (1 << j)] | g[j];    
     84 
     85     fac[0] = 1;
     86     for (int i = 1; i <= n; i++)
     87         fac[i] = mul(fac[i - 1], i);
     88     _fac[n] = inv(fac[n], Mod);
     89     for (int i = n; ~i; i--)
     90         _fac[i - 1] = mul(_fac[i], i);
     91     
     92     f[0] = 1;
     93     for (int s = 0; s < all - 1; s++) {
     94         if (!f[s] || !indep[s])
     95             continue;
     96         int ban = adj[s] | s;
     97         for (int i = 0; i < n; i++) {
     98             if (((ban >> i) & 1))
     99                 continue;
    100             f[s | (1 << i)] = add(f[s | (1 << i)], mul(f[s], permu(n - bit[ban] - 1, bit[g[i]] - bit[ban & g[i]])));
    101         }
    102     }
    103     int res = 0;
    104     for (int i = 1; i < all; i++)
    105         if (indep[i] && bit[i] == mx)
    106             res = add(res, f[i]);
    107     res = mul(res, _fac[n]);
    108     printf("%d
    ", res);
    109 }
    110 
    111 int main() {
    112     init();
    113     solve();
    114     return 0;
    115 }
    Problem A

    Problem B 猎人杀

    题目大意

      (原题题意过于简洁不需要大意)

      考虑求出在$1$被消灭掉后,剩下的集合为$S$的概率$f_S$。

      发现直接求它不好求,考虑求出剩下的集合包含$S$时的概率$g_S$。

      我们希望求$f_{varnothing}$。

      我们发现这个分母的变化会使得事情变得毒瘤起来,考虑被打死的人不会退出游戏,这样不会改变要求的概率。

      设$A = sum_{i = 1}^{n}w_i$,$B = sum_{i in S}w_i$,那么有:

    $egin{align} g_s &= frac{w_1}{A}sum_{i = 0}^{infty}left ( 1 - frac{B + w_1}{A} ight )^{i} \ &= frac{w_{1}}{A}cdot frac{1}{1 - left(1 - frac{B +w_1}{A} ight )} \ &= frac{w_1}{B + w_1 }end{align}$

      因为剩下的集合不同的两个事件是互斥的,所以有:

    $egin{align} g_s = sum_{tsubseteq Uwedge ssubseteq t}f_{t}end{align}$

      反演得到:

    $egin{align} f_s = sum_{tsubseteq Uwedge ssubseteq t} (-1)^{|t| - |s|}g_tend{align}$

      因为$w$的和不超过$10^5$,考虑求出项$frac{w_{1}}{w_{1} + B}$的系数。

      直接构造一个函数$G(x) = prod_{i = 2}^{n}(1 - x^{w_i})$,用分治NTT求出来就好了。

    Code

      1 /**
      2  * loj
      3  * Problem#2541
      4  * Accepted
      5  * Time: 940ms
      6  * Memory: 7084k
      7  */
      8 #include <bits/stdc++.h>
      9 using namespace std;
     10 typedef bool boolean;
     11 #define ll long long
     12 using std::reverse;
     13 
     14 // Polynomial Template
     15 
     16 template <typename T>
     17 void pfill(T* pst, const T* ped, T val) {
     18     for ( ; pst != ped; *(pst++) = val);
     19 }
     20 
     21 template <typename T>
     22 void pcopy(T* pst, const T* ped, T* pval) {
     23     for ( ; pst != ped; *(pst++) = *(pval++));
     24 }
     25 
     26 const int N = 262144;
     27 const int M = 998244353;
     28 const int inv2 = (M + 1) >> 1;
     29 const int g = 3;
     30 const int bzmax = 18;
     31 
     32 void debug(int *f, int len) {
     33     for (int i = 0; i < len; i++)
     34         std :: cerr << f[i] << " ";
     35     std :: cerr << '
    ';
     36 }
     37 
     38 int add(int a, int b) {
     39     return ((a += b) >= M) ? (a - M) : (a);
     40 }
     41 
     42 int sub(int a, int b) {
     43     return ((a -= b) < 0) ? (a + M) : (a);
     44 }
     45 
     46 int mul(int a, int b) {
     47     return a * 1ll * b % M;
     48 }
     49 
     50 int qpow(int a, int p) {
     51     if (p < 0)
     52         p += M - 1;
     53     int rt = 1, pa = a;
     54     for ( ; p; p >>= 1, pa = pa * 1ll * pa % M)
     55         if (p & 1)
     56             rt = rt * 1ll * pa % M;
     57     return rt;
     58 }
     59 
     60 class NTT {
     61     public:
     62         int gn[1 << (bzmax + 2)], rgn[1 << (bzmax + 2)];
     63         
     64         NTT() {
     65             int *p = gn, *_p = rgn;
     66             for (int i = 0, l = 2; i < bzmax; i++, l <<= 1) {
     67 //                gn[i] = qpow(g, (M - 1) / l);
     68 //                rgn[i] = qpow(g, -(M - 1) / l);
     69                 int tmp = 1;
     70                 int wn = qpow(g, (M - 1) >> (i + 1));
     71                 int _wn = qpow(g, - ((M - 1) >> (i + 1)));
     72                 for (int j = 0; j < l; j++)
     73                     *(p++) = tmp, tmp = mul(tmp, wn);
     74                 tmp = 1;
     75                 for (int j = 0; j < l; j++)
     76                     *(_p++)= tmp, tmp = mul(tmp, _wn);
     77 //                cerr << i << " " << cnt << '
    ';
     78             }
     79         }
     80         
     81         void rader(int *f, int len) {
     82             for (int i = 1, j = len >> 1, k; i < len - 1; i++, j += k) {
     83                 if (i < j)
     84                     std::swap(f[i], f[j]);
     85                 for (k = len >> 1; j >= k; j -= k, k >>= 1);
     86             }
     87         }
     88 
     89         void operator () (int* f, int len, int sign) {
     90             rader(f, len);
     91             const int *p = ((sign > 0) ? (gn) : (rgn));
     92             for (int b = 2; b <= len; b <<= 1) {
     93 //                int wn = ((sign > 0) ? (gn[t]) : (rgn[t])), w = 1, hb = b >> 1;
     94                 const int * const pc = p;
     95                 const int hb = b >> 1;
     96                 for (int i = 0; i < len; i += b, p = pc)
     97                     for (int j = i; j < i + hb; j++) {
     98                         int a = f[j], b = *p++ * 1ll * f[j + hb] % M;
     99                         f[j] = add(a, b);
    100                         f[j + hb] = sub(a, b);
    101                     }
    102                 p = p + b;
    103             }
    104 
    105             if (sign == -1) {
    106                 int invlen = qpow(len, M - 2);
    107                 for (int i = 0; i < len; i++)
    108                     f[i] = f[i] * 1ll * invlen % M;
    109             }
    110         }
    111 
    112         int correctLen(int n) {
    113             int t = 1;
    114             for ( ; t < n; t <<= 1);
    115             return t;
    116         }
    117 
    118 }NTT;
    119 
    120 typedef vector<int> Poly;
    121 
    122 Poly operator * (Poly a, Poly b) {
    123     int n = (signed) (a.size() + b.size()) - 1;
    124     if (n < 64) {
    125         Poly rt (n);
    126         pfill(rt.data(), rt.data() + n, 0);
    127         for (unsigned i = 0; i < a.size(); i++)
    128             for (unsigned j = 0; j < b.size(); j++)
    129                 rt[i + j] = add(rt[i + j], mul(a[i], b[j]));
    130         return rt;
    131     }
    132     int t = NTT.correctLen(n);
    133     Poly rt (t);
    134     a.resize(t), b.resize(t);
    135     NTT(a.data(), t, 1);
    136     NTT(b.data(), t, 1);
    137     for (int i = 0; i < t; i++)
    138         rt[i] = mul(a[i], b[i]);
    139     NTT(rt.data(), t, -1);
    140     rt.resize(n);
    141     return rt;
    142 }
    143 
    144 Poly dividing(int n, int* a) {
    145     if (n == 1) {
    146         Poly rt (*a + 1);
    147         pfill(rt.data(), rt.data() + *a + 1, 0);
    148         rt[*a] = M - 1, rt[0] = 1;
    149         return rt;
    150     }
    151     int sum = 0, L = 0, s = *a;
    152     for (int i = 0; i < n; i++)
    153         sum += a[i];
    154     sum >>= 1;
    155     for (int i = 1; i < n; s += a[i], i++)
    156         if (s + a[i] > sum) {
    157             L = i;
    158             break;
    159         }
    160     return dividing(L, a) * dividing(n - L, a + L);
    161 }
    162 
    163 int n, s;
    164 int *w;
    165 
    166 inline void init() {
    167     scanf("%d", &n);
    168     w = new int[(n + 1)];
    169     for (int i = 0; i < n; i++) {
    170         scanf("%d", w + i);
    171         if (i > 0)
    172             s += w[i];
    173     }
    174 }
    175 
    176 inline void solve() {
    177     if (n == 1) {
    178         puts("1");
    179         return;
    180     }
    181     sort(w + 1, w + n);
    182     Poly p = dividing(n - 1, w + 1);
    183     int res = 1;
    184     for (int i = 1; i <= s; i++)
    185         if (p[i])
    186             res = add(res, mul(mul(w[0], p[i]), qpow(add(w[0], i), -1)));    
    187     printf("%d
    ", res);
    188 }
    189 
    190 int main() {
    191     init();
    192     solve();
    193     return 0;
    194 }
    Problem B

    Problem C 随机游走

    题目大意

      (原题题意过于简洁不需要大意)

    Solution 1

      设$f_{s, i}$表示当前在点$i$,走完$s$中包含的点期望还需要多少步。

      对于非根节点的方程可以化为$f_{s,i} = kcdot f_{s', fa_i} + b$的形式,然后两遍dfs就行了。

    Code

      1 /**
      2  * loj
      3  * Problem#2542
      4  * Accepted
      5  * Time: 997ms
      6  * Memory: 37116k
      7  */
      8 #include <iostream>
      9 #include <cstdlib>
     10 #include <cstdio>
     11 #include <vector>
     12 using namespace std;
     13 typedef bool boolean;
     14 
     15 const int Mod = 998244353;
     16 
     17 int add(int a, int b) {
     18     return ((a += b) >= Mod) ? (a - Mod) : (a); 
     19 }
     20 
     21 int sub(int a, int b) {
     22     return ((a -= b) < 0) ? (a + Mod) : (a);
     23 }
     24 
     25 int mul(int a, int b) {
     26     return a * 1ll * b % Mod;
     27 }
     28 
     29 void exgcd(int a, int b, int& x, int& y) {
     30     if (!b)
     31         x = 1, y = 0;
     32     else {
     33         exgcd(b, a % b, y, x);
     34         y -= (a / b) * x;
     35     }
     36 }
     37 
     38 int inv(int a, int n) {
     39     int x, y;
     40     exgcd(a, n, x, y);
     41     return (x < 0) ? (x + n) : (x);
     42 }
     43 
     44 const int N = 18, S = 1 << N;
     45 
     46 typedef class Value {
     47     public:
     48         int k, b;
     49 
     50         Value(int k = 0, int b = 0) : k(k), b(b) {    }
     51 }Value;
     52 
     53 int n, q, X;
     54 int msk_all;
     55 Value f[S][N];
     56 vector<int> g[N];
     57 
     58 inline void init() {
     59     scanf("%d%d%d", &n, &q, &X), --X;
     60     for (int i = 1, u, v; i < n; i++) {
     61         scanf("%d%d", &u, &v);
     62         --u, --v;
     63         g[u].push_back(v);
     64         g[v].push_back(u);
     65     }
     66     msk_all = (1 << n) - 1;
     67 }
     68 
     69 void dfs1(int p, int S, int Fa) {
     70     int deg = (signed) g[p].size(), coef = deg, cont = deg, nS;
     71     for (int i = 0, e; i < deg; i++) {
     72         if ((e = g[p][i]) == Fa)
     73             continue;
     74         nS = S & (msk_all ^ (1 << e));
     75         dfs1(e, S, p);
     76         if (nS ^ S) {
     77             cont = add(cont, f[nS][e].b);
     78         } else {
     79             coef = sub(coef, f[S][e].k);
     80             cont = add(cont, f[S][e].b);
     81         }
     82     }
     83         
     84     if ((1 << p) & S)
     85         return;
     86 
     87     int _coef = inv(coef, Mod);
     88     if (p == X) {
     89         f[S][p] = Value(0, mul(cont, _coef));    
     90     } else {
     91         f[S][p] = Value(_coef, mul(_coef, cont));
     92     }
     93 }    
     94 
     95 void dfs2(int p, int S, int Fa) {
     96     if (p != X && !((1 << p) & S)) {
     97         int nS = S & (msk_all ^ (1 << Fa));
     98         f[S][p].b = add(mul(f[S][p].k, f[nS][Fa].b), f[S][p].b);
     99         f[S][p].k = 0;
    100     }
    101 
    102     for (int i = 0, e; i < (signed) g[p].size(); i++) {
    103         if ((e = g[p][i]) == Fa)
    104             continue;
    105         dfs2(e, S, p);
    106     }
    107 }
    108 
    109 inline void solve() {
    110     for (int s = 1; s <= msk_all; s++) {
    111         dfs1(X, s, -1);
    112         dfs2(X, s, -1);
    113     }
    114 
    115     int K, msk;    
    116     while (q--) {
    117         scanf("%d", &K);
    118         msk = 0;
    119         for (int i = 0, x; i < K; i++)
    120             scanf("%d", &x), msk |= (1 << (x - 1));
    121         msk = msk & (msk_all ^ (1 << X));
    122         printf("%d
    ", f[msk][X].b);
    123     }
    124 }
    125 
    126 int main() {
    127     init();
    128     solve();
    129     return 0;
    130 }
    Problem C

    Solution 2

      用最值反演把问题转化成求走到$s$中任意一个点的期望。

      假设当前考虑的集合是$s$,设$f_i$表示当前在点$i$,走到$s$中任意一个点的期望。

      然后同样的做法dp一下就行了。

    Code

      1 /**
      2  * loj
      3  * Problem#2542
      4  * Accepted
      5  * Time: 617ms
      6  * Memory: 1232k
      7  */
      8 #include <iostream>
      9 #include <cstdlib>
     10 #include <cstdio>
     11 #include <vector>
     12 using namespace std;
     13 typedef bool boolean;
     14 
     15 const int Mod = 998244353;
     16 
     17 int add(int a, int b) {
     18     return ((a += b) >= Mod) ? (a - Mod) : (a); 
     19 }
     20 
     21 int sub(int a, int b) {
     22     return ((a -= b) < 0) ? (a + Mod) : (a);
     23 }
     24 
     25 int mul(int a, int b) {
     26     return a * 1ll * b % Mod;
     27 }
     28 
     29 void exgcd(int a, int b, int& x, int& y) {
     30     if (!b)
     31         x = 1, y = 0;
     32     else {
     33         exgcd(b, a % b, y, x);
     34         y -= (a / b) * x;
     35     }
     36 }
     37 
     38 int inv(int a, int n) {
     39     int x, y;
     40     exgcd(a, n, x, y);
     41     return (x < 0) ? (x + n) : (x);
     42 }
     43 
     44 const int N = 18, S = 1 << N;
     45 
     46 typedef class Value {
     47     public:
     48         int k, b;
     49 
     50         Value(int k = 0, int b = 0) : k(k), b(b) {    }
     51 }Value;
     52 
     53 int n, q, X;
     54 int msk_all;
     55 Value f[N];
     56 int F[S];
     57 vector<int> g[N];
     58 
     59 inline void init() {
     60     scanf("%d%d%d", &n, &q, &X), --X;
     61     for (int i = 1, u, v; i < n; i++) {
     62         scanf("%d%d", &u, &v);
     63         --u, --v;
     64         g[u].push_back(v);
     65         g[v].push_back(u);
     66     }
     67     msk_all = (1 << n) - 1;
     68 }
     69 
     70 void dfs1(int p, int S, int Fa) {
     71     int deg = (signed) g[p].size(), coef = deg, cont = deg, nS;
     72     for (int i = 0, e; i < deg; i++) {
     73         if ((e = g[p][i]) == Fa)
     74             continue;
     75         nS = S & (1 << e);
     76         dfs1(e, S, p);
     77         if (!nS) {
     78             coef = sub(coef, f[e].k);
     79             cont = add(cont, f[e].b);
     80         }
     81     }
     82         
     83     int _coef = inv(coef, Mod);
     84     if ((1 << p) & S)
     85         f[p] = Value(0, 0);
     86     else if (p == X) {
     87         f[p] = Value(0, mul(cont, _coef));    
     88     } else {
     89         f[p] = Value(_coef, mul(_coef, cont));
     90     }
     91 }    
     92 
     93 void dfs2(int p, int S, int Fa) {
     94     if (p != X && !((1 << p) & S)) {
     95         f[p].b = add(mul(f[p].k, f[Fa].b), f[p].b);
     96         f[p].k = 0;
     97     }
     98 
     99     for (int i = 0, e; i < (signed) g[p].size(); i++) {
    100         if ((e = g[p][i]) == Fa)
    101             continue;
    102         dfs2(e, S, p);
    103     }
    104 }
    105 
    106 inline void solve() {
    107     for (int s = 1, bit = 0; s <= msk_all; s++) {
    108         if (s & (1 << X)) {
    109             F[s] = 0;
    110             continue;
    111         }
    112         dfs1(X, s, -1);
    113         dfs2(X, s, -1);
    114         F[s] = f[X].b, bit = 0;
    115         for (int s0 = s; s0; s0 -= (s0 & (-s0)), bit ^= 1);
    116         if (!bit)
    117             F[s] = Mod - F[s];
    118     }
    119 
    120     for (int i = 0; i < n; i++)
    121         for (int j = 0; j <= msk_all; j++)
    122             if ((j >> i) & 1)
    123                 F[j] = add(F[j], F[j ^ (1 << i)]);
    124 
    125     int K, msk;    
    126     while (q--) {
    127         scanf("%d", &K);
    128         msk = 0;
    129         for (int i = 0, x; i < K; i++)
    130             scanf("%d", &x), msk |= (1 << (x - 1));
    131         msk = msk & (msk_all ^ (1 << X));
    132         printf("%d
    ", F[msk]);
    133     }
    134 }
    135 
    136 int main() {
    137     init();
    138     solve();
    139     return 0;
    140 }
    Problem C
  • 相关阅读:
    Gitlab 进首页报错500 Whoops。 访问仓库错误码503
    iptables设置Linux全局代理
    元素到底部位置判断
    行为型设计模式:职责链模式
    Win7SP1安装.net 4.6 4.7 4.8
    深入理解并行编程 电子书 pdf
    CUDA C编程权威指南 第二版 电子书 pdf
    程序员修炼之道 第二版 电子书 pdf
    linux多线程服务端编程 电子书 pdf
    Clean Craftsmanship: Disciplines, Standards, and Ethics 电子书 pdf
  • 原文地址:https://www.cnblogs.com/yyf0309/p/10092898.html
Copyright © 2020-2023  润新知