HDU 5229 - ZCC loves strings(博弈+概率)

题意

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

解析:

首先从n个字符串中选取2个字符串的可能有 C(n,2) 种。
然后给你两个字符串 a,b 肯定存在着先手必胜和先手必败两种状态。
关键是如何确定这两种状态。
引用一下官方题解:

结论:对于串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 的贡献。累加即可。

AC代码

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <map>
#include <string>
using namespace std;
typedef long long ll;
const int N = 200005;
map<ll, int> mp;
map<ll, int>::iterator it;
char str[N];
ll Hash(char *str) {
    ll sum = 0;
    while(*str) {
        sum = sum*256 + *(str++);
    }
    return sum;
}
ll gcd(ll a, ll b) {
    if(b == 0) return a;
    else return gcd(b, a%b);
}
int main() {
    //freopen("in.txt", "r", stdin);
    int T, n;
    scanf("%d", &T);
    while(T--) {
        mp.clear();
        scanf("%d", &n);
        ll ans = 0, odd = 0, even = 0, equal = 0;
        for(int i = 0; i < n; i++) {
            scanf("%s", str);
            mp[Hash(str)]++;
            int len = strlen(str);
            if(len & 1) odd++;
            else even++;
        }
        for(it = mp.begin(); it != mp.end(); it++) {
            ll tmp = it->second;
            equal += tmp*(tmp-1)/2;
        }
        ll nu = even*odd + equal, de = n*(n-1)/2;
        ll g = gcd(nu, de);
        printf("%lld/%lld\n", nu/g, de/g);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值