D. Even String

题目链接:https://codeforces.com/contest/2086/problem/D

题意:

给定26个字母的出现次数,构造一个字符串

要求对于相同的一种字母,其任意个两两地在字符串的距离为偶数

思路:

要求同种字母的距离为偶数,即同种字母都在字符串奇数/偶数位置。((pos1-pos2)%2==0)

由于每个字母出现次数给定,则字符串长度已知

记odd为奇数位置的数目

那么我们只需要对26个字母进行01背包,挑选一些字母放在奇数位置,剩余的放在偶数位置。这是大体的方案数

记f[i]:为奇数位置已经填满了i个数时的方案数

f[odd]即为上述大体的方案数


那么枚举26个字母

以及j

f[j]=f[j]+f[j-a[i]]

第一项为不把这个字母放在奇数位置时的方案,第二项为把这个字母放在奇数位置时的方案


对于一个小方案,其方案数由多重集公式为:总数的阶乘 / 同种数的阶乘 的乘积

由于大数取模,需要用到阶乘的预处理以及乘法逆元

int fact[maxn];
int infact[maxn];
int ksm(int a,int b,int p){
    int res=1;
    while(b){
        if(b&1)res=res*a%p;
        a=a*a%p;
        b>>=1;
    }
    return res;
}
void solve(){
    vector<int>a(27);
    int sum=0;
    rep(i,1,26){
        cin>>a[i];
        sum+=a[i];
    }
    int odd,even;
    if(sum%2==0)odd=even=sum/2;
    else {
        odd=sum/2;
        even=sum/2+1;
    }
    vector<int>f(odd+1,0);
    f[0]=1;
    for(int i=1;i<=26;i++){
        if(a[i]==0)continue;
        for(int j=odd;j>=a[i];j--){
            f[j]=(f[j]%mod+f[j-a[i]]%mod)%mod;
        }
    }
    int cnt=f[odd];

    int inv =1;
    for(int i=1;i<=26;i++){
        inv=inv*infact[a[i]]%mod;
    }
    
    int ans=((cnt*fact[odd])%mod * fact[even]%mod)*inv%mod;

    cout<<ans<<endl;
}

signed main()
{
  ios::sync_with_stdio(false),cin.tie(0);
  int T;cin>>T;
  fact[0]=infact[0]=1;
  for(int i=1;i<maxn;i++){
    fact[i]=fact[i-1]*i%mod;
    infact[i]=infact[i-1]*ksm(i,mod-2,mod)%mod;
  }
  while(T--){
  solve();
  }

  return 0;
}
posted @ 2025-05-08 21:35  Marinaco  阅读(44)  评论(0)    收藏  举报
//雪花飘落效果