题解 Game with Strings
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;
}