Live2D

题解 Game with Strings

link

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;
}
posted @ 2021-10-17 16:39  Dark_Romance  阅读(27)  评论(0编辑  收藏  举报