考场的SB经验不再分享
case 0:
一道组合计数的水题,具体不再讲可以看以前的相似题
case 1:
很明显的卡特兰计数,我们把长度为n的序列看成01串
由此可知我们需要满足从1——n中前缀1的数量不少于前缀0的数量
case 2:
满足可以在坐标轴上移动
设f[i]表示第i步回到原点,我们枚举第j步第一次回到起点
那么f[i]数组里就不会出现重复,这样可以保证正确性
同时要再次用到卡特兰数:
我们发现定义的特殊j是第一次回到起点,但cal中可以多次回到起点
但我们可以发现只要我们满足在1-j-1满足前缀和>=1即可,这样我们可以
发现现在序列一部分确定设正方向为1
1 1 .........0 0
这样中间部分就又是一个cal,这样我们直接乘cal(j/2-1)即可
(注意可能j是四个方向,于是乘4)
case 3:
同时在两轴及第一象限
直接用组合数,乘两个方向的cal即可
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<algorithm> 6 #include<cmath> 7 #include<stack> 8 #include<map> 9 #include<queue> 10 #define ps push_back 11 #define MAXN 1000001 12 #define ll long long 13 using namespace std; 14 ll n; 15 const ll mod=1000000007; 16 ll jie[MAXN],ni[MAXN],ni_c[MAXN]; 17 ll C(ll x,ll y) 18 { 19 if(y>x)return 0; 20 return jie[x]*ni_c[y]%mod*ni_c[x-y]%mod; 21 } 22 ll cal(ll x) 23 { 24 return C(x*2,x)*ni[x+1]%mod; 25 } 26 ll f[MAXN]; 27 int main() 28 { 29 ll orz; 30 scanf("%lld%lld",&n,&orz); 31 jie[0]=1;jie[1]=1; 32 ni[0]=1;ni[1]=1; 33 ni_c[0]=1;ni_c[1]=1; 34 for(ll i=2;i<=2*n+10;++i) 35 { 36 jie[i]=(jie[i-1]*i)%mod; 37 ni[i]=((mod-mod/i)*ni[mod%i])%mod; 38 ni_c[i]=(ni_c[i-1]*ni[i])%mod; 39 } 40 ll ans=0; 41 if(orz==0) 42 { 43 for(ll i=0;i<=n;i+=2) 44 { 45 ans=(ans+C(n,i)*C(i,i/2)%mod*C(n-i,(n-i)/2))%mod; 46 } 47 printf("%lld ",ans%mod); 48 } 49 else if(orz==1) 50 { 51 if(n%2==1) 52 printf("0 "); 53 else 54 printf("%lld ",(C(n,n/2)%mod*ni[n/2+1]%mod+mod)%mod); 55 } 56 else if(orz==3) 57 { 58 for(ll i=0;i<=n;i+=2) 59 { 60 ll th=C(n,i); 61 if((n-i)%2==1)continue; 62 ans=(ans+th*cal(i/2)%mod*cal((n-i)/2))%mod; 63 } 64 printf("%lld ",ans); 65 } 66 else if(orz==2) 67 { 68 f[0]=1; 69 for(ll i=2;i<=n;i+=2) 70 { 71 for(ll j=0;j<=i;j+=2) 72 { 73 f[i]=(f[i]+4*f[i-j]*cal(j/2-1))%mod; 74 } 75 } 76 printf("%lld ",f[n]); 77 } 78 }