bc41第二题:
题意:两个人有 n 个串,随机选出两个串,可以进行这样的操作:①选一个串消去最后一个字符,②若两串相同则可以全部消去两串
若到某个人时正好消去两个串,则这个人胜另一人负,问先手胜概率;
首先就是判断什么情况先手胜:
①当两个串一开始就相同的情况:先手可以直接消去两个串,则先手胜;
②当两个串长度和为奇数的情况:先手始终消长度短的串,那么两串长度始终不相等,则后手也被迫执行操作①,按顺序都执行操作①那么最后一个字符会被先手消去,先手胜;
而后手胜的情况:
两串长度和为偶数且两串不相同,此时先手无论先消去哪个串的最后一个字符,后手只需要始终删去短串的最后一个字符,可以使两个串长度始终不等,则两人都执行操作①,后手胜;
那么问题就是任取两串,长度和为奇数或两串相同的概率。
计算方式就是读入时计录长度分别奇数及偶数的串的个数以及每种串出现多少次。两串长度和奇数的种类数就是奇数串个数×偶数串个数;两串相同的种类数就是对每种串,个数为k,种类数k*(k-1)/2;这些总和除以总数 n*(n-1)/2 就得到结果,约分形式就是同除以 gcd即可;
但是由于我蠢!我特判了概率 0 时输出 “0 / 总和”,实际该输出 “0/1”
就这样又wa一发```
#include<iostream>
#include<cstdio>
#include<cstring>
#include<map>
#include<string>
using namespace std;
typedef long long ll; ll gcd(ll a,ll b){
for(;a>&&b>;a>b?a%=b:b%=a);
return a+b;
} int main(){
int T;
while(scanf("%d",&T)!=EOF){
while(T--){
int n;
scanf("%d",&n);
map<string,int>m;
ll ji=,ou=;
m.clear();
int i;
for(i=;i<=n;i++){
string a;
cin>>a;
m[a]++;
if(a.length()%){
ji++;
}
else ou++;
}
ll cnt=;
cnt=ji*ou;
for(map<string,int>::iterator it=m.begin();it!=m.end();it++){
if(it->second>){ cnt+=((it->second)*((it->second)-)/);
}
}
ll sum=n*(n-)/;
if(cnt==)printf("0/1\n");
else{
ll g=gcd(cnt,sum);
printf("%lld/%lld\n",cnt/g,sum/g);
}
}
}
return ;
}