题目
怎么说呢。。。这道sb题我是傻掉惹。。。想得挺麻烦的。。。只能说基础不扎实吧。。。如果要看简洁的题解,请移步xyz32768dalao的博客。
我们可以找出不符合条件的字符串的数量(num),将总数减去。
显然,对于一个字符串的前(k)个字符,如果已经不满足条件了,那后面的字符就可以随便填了。
为了避免重复计算,我们设(f_i)为前(2i-2)个字符合法,但前(2i-1)个字符不合法的数量,显然(i)等于前(2i-1)个字符中(0)的数量。
故(num=sumlimits_{i=1}^m{f_i cdot frac{(n+m-2i+1)!}{(n-i+1)!(m-i)!}}) (使用可重排列公式)
设(g_i= C_{2i}^{i}),则(f_i= C_{2i-1}^{i-1}-sumlimits_{j=1}^{i-1}{g_jf_{i-j}}) 可以发现这是一个卷积的形式,所以用分治FFT优化
然后。。。额。。。求出(f)的前几项,(1,1,2,5,14 cdots) 发现将(f)的下标减(1)即为卡特兰数,故预处理阶乘逆元可在(O(n))的复杂度下通过。
完结撒花~(大雾
({frak{code:}})
#include<bits/stdc++.h>
#define IL inline
#define LL long long
using namespace std;
const int N=2e6+3,p=20100403;
int n,m;
LL f[N],fac[N],inv[N],ans;
IL int in(){
char c;int f=1;
while((c=getchar())<'0'||c>'9')
if(c=='-') f=-1;
int x=c-'0';
while((c=getchar())>='0'&&c<='9')
x=x*10+c-'0';
return x*f;
}
IL LL ksm(LL a,LL b){
LL c=1;
while(b){
if(b&1) c=c*a%p;
a=a*a%p,b>>=1;
}
return c;
}
void exgcd(LL a,LL b,LL &x,LL &y){
if(!b){x=1,y=0;return;}
exgcd(b,a%b,y,x);
y-=a/b*x;
}
IL LL C(LL a,LL b){return fac[a]*inv[b]%p*inv[a-b]%p;}
int main()
{
LL x,y,z;
n=in(),m=in();
fac[0]=inv[0]=f[1]=1;
for(int i=1;i<=n+m;++i) fac[i]=fac[i-1]*i%p;
exgcd(fac[n+m],p,inv[n+m],x);
inv[n+m]=(inv[n+m]%p+p)%p;
for(int i=n+m-1;i;--i) inv[i]=inv[i+1]*(i+1)%p;
for(int i=2;i<=m;++i) f[i]=C(2*(i-1),i-1)*fac[i-1]%p*inv[i]%p;
for(int i=1;i<=m;++i) ans=(ans+f[i]*fac[n+m-i*2+1]%p*inv[n-i+1]%p*inv[m-i])%p;
ans=(fac[n+m]*inv[n]%p*inv[m]%p-ans+p)%p;
printf("%lld
",ans);
return 0;
}