codeforces 931E. Game with String(思维+预处理+概率)

题意:给你一个小写字母字符串,A会把这个序列截断把后半部分补到前半部分之前,形成新的序列,然后告诉你这个新的序列的第一个字母是什么,并且允许你询问一次,这个新序列中任意一个位置的字母是什么,并告诉你答案,问你能否唯一的知道原序列被截断的位置,如果可以,则算你赢,问你赢的最大概率是多少。

思路:我们可以预处理出dp[i][j][k]:字母i和字母j距离为k一共在原序列中出现了几次。统计答案的时候,只需要对于每一个字母i,枚举距离为k的时候,看有几个字母j满足dp[i][j][k]=1,(这个过程等价于,告知你的第一个位置的字母是i,假设你唯一的知道这个原序列被截断的位置为k,那么A告诉你的字母为j的时候是否满足题意),显然对于每一个字母i,找到一个满足dp[i][j][k]的字母j最多的 k m a x ,将其累加起来即可。(这个过程等价于,告知你的第一个位置的字母是i,你将选择询问距离为 k m a x 的那个字母j,这个举动将使你有最大的胜率)

#include <bits/stdc++.h>
using namespace std;
int cnt[26][26][5000 + 5];
int vis[26];
int main()
{
    string str;
    cin >> str;
    for(int i = 0; i < str.size(); i++)
    {
        vis[str[i] - 'a'] = 1;
        for(int dist = 1; dist < str.size(); dist++)
        {
            cnt[str[i] - 'a'][str[(i + dist) % str.size()] - 'a'][dist]++;
        }
    }
//    puts("?");
    double ans = 0;
    for(int i = 0; i < 26; i++)
    {
        int mx = 0;
        for(int dist = 1; dist < str.size(); dist++)
        {
            int temp = 0;
            for(int j = 0; j < 26; j++)
            {
                if(cnt[i][j][dist] == 1)    temp++;
            }
            mx = max(mx, temp);
        }
        ans += 1.0 * mx / str.size();
    }
    printf("%.8f\n", ans);

    return 0;

猜你喜欢

转载自blog.csdn.net/qq_29556211/article/details/79524639