題解 Game with Strings
阿新 • • 發佈:2021-10-17
Solution
首先 \(\Theta(nm2^m)\) 的應該挺好想的吧?直接列舉選的是哪個就好了?
考慮如何做到 \(\Theta(m2^m)\) ,可以想到的是,我們可以先求出 \(g_{s}\) 表示我在選了 \(s\) 這個狀態裡面的位置進行查詢,選了哪些無法分辨出來。
然後我們設 \(f_{S}\) 表示現在已經查詢了 \(S\) 這個集合裡面的位置還需要查詢的期望次數。然後我們就可以列舉下一次選什麼就好了。
Code
#include <bits/stdc++.h> using namespace std; #define Int register int #define int long long #define MAXN 55 template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} template <typename T> inline void chkmax (T &a,T b){a = max (a,b);} template <typename T> inline void chkmin (T &a,T b){a = min (a,b);} string S[MAXN]; double f[1 << 20]; int n,m,siz[1 << 20],g[1 << 20]; signed main(){ read (n); for (Int i = 1;i <= n;++ i) cin >> S[i]; m = S[1].length(); for (Int i = 1;i <= n;++ i) for (Int j = i + 1;j <= n;++ j){ int tmp = 0; for (Int k = 0;k < m;++ k) tmp |= ((S[i][k] == S[j][k]) << k); g[tmp] |= (1ll << i - 1),g[tmp] |= (1ll << j - 1); } for(int i=0;i<m;++i){ for(int j=(1<<m)-1;j>=0;--j) if(!((j>>i)&1)) g[j]|=g[j^(1<<i)]; } for (Int s = 0;s < (1 << m);++ s){ int cnt = 0; for (Int i = 1;i <= n;++ i) cnt += (g[s] >> i - 1 & 1); g[s] = cnt; } for (Int s = (1 << m) - 1;s >= 0;-- s){ if (!g[s]) continue; int cnt = 0; for (Int i = 1;i <= m;++ i) cnt += (!(s >> i - 1 & 1)); for (Int i = 1;i <= m;++ i) if (!(s >> i - 1 & 1)) f[s] += (f[s | (1 << i - 1)] * g[s | (1 << i - 1)] * 1.0 / g[s] + 1) * 1.0 / cnt; } printf ("%.9f\n",f[0]); return 0; }