hdu 5229 必胜策略

来源:互联网 发布:数控编程人员工资待遇 编辑:程序博客网 时间:2024/05/01 22:47

题意

ZCC有N个字符串,他正在和Miss G.用这N个字符串玩一个小游戏。ZCC会从这N个串中等概率随机选两个字符串(不可以是同一个)。然后,ZCC和Miss G.轮流操作。Miss G.总是先操作的。在每轮中,操作者可以选择操作A或操作B。
操作A:在两个串中选择一个当前非空的串,然后在这个串的末尾删去一个字符。
操作B: 若当前两个串完全相同且非空,则可以使用这个操作。此时两个串都被清空。
不能操作的玩家输掉了这个游戏。
ZCC想要知道他输掉游戏的概率是多少(也就是Miss G.获胜的概率)。

思路

结论:对于串a和b,游戏中先手必胜当且仅当|a|+|b|为奇数或a=b.
我们按|a|+|b|的大小从小到大考虑所有的情况。
当|a|+|b|=0时,显然先手必败,符合结论。
假设已经证明了|a|+|b|=k的所有情况满足结论,现在考虑|a|+|b|=p的情况。
若p是奇数,先手只需要选择长度较短的不为空的串,并使用A操作,就可以转移到|a|+|b|为偶数并且两个串不相等或者两个串均为空的情况,这种情况先手必败,故此时先手必胜。
若p是偶数,如果两个串相等,显然先手只需要选择使用B操作就能获得胜利了。否则,无论先手如何操作,都只能转移到|a|+|b|为奇数的先手必胜的情况。故此时先手必败。
因此,按顺序考虑每一个串,求得在其之前出现的串中,长度奇偶性与其不同的串共有x个,与其完全相同的串有y个,则对答案有x+y的贡献。累加即可。

#include <iostream>#include<stdio.h>#include<string.h>#include<algorithm>#include <map>#define ll long longusing namespace std;map<string , int>  mp;int len[2];ll gcd(ll a,ll b){    if(b==0)        return a;    return gcd(b,a%b);}int main(){    int t;    scanf("%d",&t);    while(t--)    {        memset(len,0,sizeof(len));        mp.clear();        int n;        scanf("%d",&n);        ll ans=0;        string str;        for(int i=0;i<n;i++)        {            cin>>str;            if(str.length()&1)           {               ans+=mp[str]+len[0];//len[0]表示偶数串的个数,len[1]是奇数串的个数               len[1]++;           }            else              {                  ans+=mp[str]+len[1];                  len[0]++;              }            mp[str]++;        }        ll y=n*(n-1)/2;        ll gcd2=gcd(ans,y);        ans/=gcd2,y/=gcd2;        printf("%I64d/%I64d\n",ans,y);    }}

0 0
原创粉丝点击