洛谷 P1641 [SCOI2010]生成字符串

题目

怎么说呢。。。这道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;
}
原文地址:https://www.cnblogs.com/yiqiAtiya/p/12142107.html