2024“钉耙编程”中国大学生算法设计超级联赛(1)
题目链接:Problem - 7437
题目描述:
发现当s为偶数时,(s表示字符集s的大小),如果平局的概率是p,则答案是(1-p)/2。因为两人完全随机
当s为奇数时,如果前s-1个是平局,则必定A胜,否则各1/2。则答案为(1-p)/2+p = (1+p)/2
当s为偶数时
若想要平局,需要AB两个人每次选的完全一样。所以要求每个字符的个数都是偶数。否则就不能平局
平局概率:
如果将Alice和Bob的字符串拼在一起,Alice的字符串是a1a2a3a4,Bob的字符串是b1b2b3b4
则接在一起是a1b1a2b2a3b3a4b4
s个字符,总方案数是s!。
假如有四个a,两个b,两个c,则平局的方案一定是aabbaacc/aabbaacc/ccaaaabb这样的
所以每两个相同的字符一定是挨在一起的,将字符两两绑定,还有s/2个元素,总方案数是(s/2)!
对每种字符内部排序,对第i个字符的方案数是 hi ! 。
此时,在计算每种字符内部的方案,和每两个相同字符挨在一起的方案,有一部分重复计算。
重合部分:对每种字符,两两绑定之后的方案数
例:aa1 aa2 aa3,aa2 aa1 aa3 , aa3 aa1 aa2 这个被重复计算
所以要再除以每种字符内部两两绑定后的方案数
得到答案为:
当s为奇数时
平局概率:
若想要平局,则两人选的前s-1个字符必须一样,剩下一个是第s个字符
所以必须有一种字符的是奇数个,其他字符是偶数个。否则前不可能想等,p=0
最后一个(第s个字符)必须是个数为奇数的那个字符。设hk是数量为奇数的字符,cnt是hk的数量
从hk中拿出来一个作为最后一个字符。
hk最为最后一个字符的概率是 cnt/s
最后一个确定,前边的计算方法和s是偶数时一样,但是当hi=hk时,hi要-1
得到答案为:
ac代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
using pii=pair<int,int>;
using ll = long long;
using ull = unsigned long long;
//using i128 = __int128_t;
const ll inf = 1e18;
const int mod = 998244353;
int fact[10000002];
int qmi(int a,int b,int p){
int ans=1;
while(b){
if(b&1) ans=ans*a%p;
b>>=1;
a=a*a%p;
}
return ans;
}
void init(){
fact[1]=fact[0]=1;
for(int i=1;i<=10000000;i++){
fact[i]=fact[i-1]*i%mod;
}
}
inline int infact(int val){
return qmi(fact[val],mod-2,mod);
}
void solve(){
int n,sum=0,ji=0;
cin>>n;
vector<int> cnt(200);
for(int i=1;i<=n;i++){
char ch;
int num;
cin>>ch>>num;
cnt[ch]=num;
sum+=num;
if(num&1) ji++;
}
if(sum%2==0){
//odd
if(ji){
cout<<qmi(2,mod-2,mod)<<endl;
return;
}
int p=fact[sum/2]*infact(sum)%mod;
for(int i='a';i<='z';i++){
if(!cnt[i]) continue;
p*=fact[cnt[i]];
p%=mod;
p*=infact(cnt[i]/2);
p%=mod;
}
cout<<(1-p+mod)*qmi(2,mod-2,mod)%mod<<endl;
}
else{
if(ji!=1){
cout<<qmi(2,mod-2,mod)<<endl;
return;
}
char ch;
for(int i='a';i<='z';i++){
if(cnt[i]&1){
ch=i;
break;
}
}
//cout<<"00";
int p=cnt[ch]*qmi(sum,mod-2,mod)%mod;
p*=fact[sum/2]*infact(sum-1)%mod;
p%=mod;
for(int i='a';i<='z';i++){
if(!cnt[i]) continue;
if(i!=ch) p*=fact[cnt[i]];
else p*=fact[cnt[i]-1];
p%=mod;
p*=infact(cnt[i]/2);
p%=mod;
}
cout<<(1+p)*qmi(2,mod-2,mod)%mod<<endl;
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
init();
int ct=1;
cin>>ct;
while(ct--){
solve();
}
return 0;
}