CF482C Game with Strings

洛谷传送门 CF传送门

Solution

观察发现 \(m\leq 20\) ,那么我们可以想到状压DP。

将位置压起来,设 \(f_i\) 表示此时状态为 \(i\) ,距离确定一个字符串所需要的期望,那么可得:

\[f_i=\sum_{!(i\And(1<<j)}\frac {f_{i|(1<<j)}}{tot}+1 \]

其中 \(tot\) 表示状态 \(i\) 中还有几个位置没问(也就是还有几个 \(0\) ),那因为询问剩余位置的概率相同,所以此方程是对的。

但是每次询问不一定就能唯一一个字符串,可能是好几个,所以需要处理出来对于每一个状态能确定几个字符串。

那么设 \(num_i\) 表示符合 \(i\) 这个状态的字符串的数量,可得:

\[f_i=\sum_{!(i\And(1<<j)}\frac {f_{i|(1<<j)}}{tot}\times \frac {num_{i|(1<<j)}}{num_i}+1 \]

详细解释一下 \(\dfrac {num_{i|(1<<j)}}{num_i}\) :首先设 \(k=i|(1<<j)\) ,那么 \(num_k\leq num_i\) ,因为 \(k\) 多了一位确定的。而 \(i\)\(num_k\) 种可能变成 \(k\) ,剩下的 \(num_i-num_k\) 是直接得到唯一确定字符串的,所以继续转移的可能就是 \(\dfrac {num_{i|(1<<j)}}{num_i}\)

好,转移方程得到了,怎么求得 \(num\) 数组呢?

这个时候,就要再来一个辅助的东西——设 \(unf_i\) 表示状态为 \(i\) 的情况下,哪些字符串是符合的,或者说是不能直接确定的(这里是拿二进制状态存串是否满足条件),因为在 \(i\) 这个状态下,某几个串表达的东西可能一样。

对于 \(unf\) 数组,直接 \(O(n^2)\) 暴力匹配即可,然后从大到小更新。

那么 \(num_i\) 就是 \(unf_i\)\(1\) 的数量了。

注意:代码中状压时枚举要往后错一位。

Code

#include<bits/stdc++.h>
#define int long long

using namespace std;
const int N=(1ll<<20)+10,M=55;
int m,n,unf[N],num[N];
char s[M][M];
double f[N];

signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++) scanf("%s",s[i]+1);
    m=strlen(s[1]+1);
    for(int i=1;i<=n;i++)
        for(int j=i+1;j<=n;j++){
            int tmp=0;
            for(int k=1;k<=m;k++)
                if(s[i][k]==s[j][k]) tmp|=(1ll<<(k-1));
            unf[tmp]|=(1ll<<(i-1)); unf[tmp]|=(1ll<<(j-1));
        }
    for(int i=(1ll<<m)-1;i>=1;i--)
        for(int j=1;j<=m;j++)
            if(i&(1ll<<(j-1))) unf[i^(1ll<<(j-1))]|=unf[i];
    for(int i=0;i<(1ll<<m);i++)
        for(int j=1;j<=n;j++)
            if(unf[i]&(1ll<<(j-1))) num[i]++;
    for(int i=(1ll<<m)-2;i>=0;i--){
        if(!num[i]) continue;
        int tot=m;
        for(int j=1;j<=m;j++)
            if(i&(1ll<<(j-1))) --tot;
        for(int j=1;j<=m;j++){
            if(i&(1ll<<(j-1))) continue;
            f[i]+=
            f[i|(1ll<<(j-1))]/(double)tot*((double)num[i|(1ll<<(j-1))]/(double)num[i]);
        }
        f[i]+=1.0;
    }
    printf("%.10lf\n",f[0]);
    return 0;
}
posted @ 2020-12-03 11:30  jasony_sam  阅读(104)  评论(0编辑  收藏  举报