题解【AGC058D】Yet Another ABC String
显然要考虑容斥。一般的容斥是枚举不合法的字符串位置,但这题不合法的字符串可能会重叠,比较难以计算。一种好的容斥方式是容斥形如 ABCABCABCA... 这样的连续段,只要每个极长连续段长度都不超过 2 就行了。
这样会产生一个新的问题:我们并不能保证连续段是极长的。我们需要找到一个容斥系数,使得长度
通过暴力多项式求逆或者手算,可以得到:
我们只关心
其中 -3 的系数是因为连续段长度为 3 的倍数时,有三种方案。整理一下:
那么我们只需要枚举右边选了几个
#include<bits/stdc++.h>
#define For(i,a,b) for(int i=(a);i<=(b);++i)
#define Rof(i,a,b) for(int i=(a);i>=(b);--i)
using namespace std;
const int Maxn=3e6,Mod=998244353;
inline int Pow(int x,int y)
{
int res=1;
while(y)
{
if(y&1) res=1ll*res*x%Mod;
x=1ll*x*x%Mod,y>>=1;
}
return res;
}
int A,B,C,n,fac[Maxn+5],inv[Maxn+5],pw[Maxn+5];
inline int F(int a,int b,int c)
{
int m=min(a,min(b,c)),res=0; if(m<0) return 0;
For(i,0,m)
{
int k=1ll*pw[i]*(i&1?Mod-1:1)%Mod;
res=(res+1ll*k*fac[a+b+c-i-i]%Mod*inv[i]%Mod*
inv[a-i]%Mod*inv[b-i]%Mod*inv[c-i])%Mod;
} return res;
}
int main()
{
cin>>A>>B>>C; n=A+B+C,fac[0]=inv[0]=pw[0]=1;
For(i,1,n) pw[i]=2*pw[i-1]%Mod;
For(i,1,n) fac[i]=1ll*fac[i-1]*i%Mod;
inv[n]=Pow(fac[n],Mod-2);
Rof(i,n-1,1) inv[i]=1ll*inv[i+1]*(i+1)%Mod;
cout<<(F(A,B,C)-F(A-1,B-1,C-1)+Mod)%Mod<<endl;
return 0;
}