cogs2287(组合数学+画柿子+NTT)
cogs都可以下数据的题,bzoj居然是权限题。
在某犇博客找到的,即使知道是ntt,刚看到时还是一脸懵逼,完全没头绪,所以就做了。
[题面](http://218.28.19.228/cogs/problem/problem.php?pid=2287)
题意:某机器人一开始在(0,0),每一次操作可以向右,向左,向下,向上走或不走。不可以在某一次操作后坐标为负数。问n次操作,最后回到(0,0)的方案数,模一个费马素数。
假设不可以不走,走n步(n为偶数),且只有一维,那就是一个卡特兰数。我依旧百度了一下,发现公式为$$C_n^{n/2}-C_n^{n/2-1}$$设为g[n]。
考虑两维的走n步的方案数,设为f[n],依然不可以不走,就有$$f[n]=\sum_{i=0}^{n}g[i]*g[n-i]*C_n^{i}$$
看起来像个卷积,把组合数拆出来,有$$f[n]=n!\sum_{i=0}^{n}\frac{g[i]}{i!}*\frac{g[n-i]}{(n-i)!}$$这就是个卷积了,上ntt就可以了。
考虑可以不走的情况,我们枚举走了i步,不走(n-i)步,有
$$ans=\sum_{i=0}^{n}f[i]*C_n^{i}$$
我觉得画柿子还是要回归本源,比如说不要追求卡特兰数的递推之类的。次方,阶乘始终是最好求的东西。
1 #include <iostream> 2 #include <fstream> 3 #include <algorithm> 4 #include <cmath> 5 #include <ctime> 6 #include <cstdio> 7 #include <cstdlib> 8 #include <cstring> 9 10 using namespace std; 11 #define mmst(a, b) memset(a, b, sizeof(a)) 12 #define mmcp(a, b) memcpy(a, b, sizeof(b)) 13 14 typedef long long LL; 15 16 const int N=400100; 17 const LL p=998244353,g=3; 18 19 int n,rev[N]; 20 21 LL cheng(LL a,LL b) 22 { 23 LL res=1ll; 24 for(;b;b>>=1,a=a*a%p) 25 if(b&1) 26 res=res*a%p; 27 return res; 28 } 29 30 void init(int lim) 31 { 32 int k=-1; 33 n=1; 34 while(n<=lim) 35 k++,n<<=1; 36 for(int i=0;i<n;i++) 37 rev[i]=(rev[i>>1]>>1) | ((i&1)<<k); 38 } 39 40 void ntt(LL *a,bool ops) 41 { 42 for(int i=0;i<n;i++) 43 if(i<rev[i]) 44 swap(a[i],a[rev[i]]); 45 for(int l=2;l<=n;l<<=1) 46 { 47 int m=(l>>1); 48 LL wn; 49 if(ops) 50 wn=cheng(g,(p-1)/l); 51 else 52 wn=cheng(g,p-1-(p-1)/l); 53 for(int i=0;i<n;i+=l) 54 { 55 LL w=1ll; 56 for(int k=0;k<m;k++) 57 { 58 LL t=a[i+k+m]*w%p; 59 a[i+k+m]=(a[i+k]-t+p)%p; 60 a[i+k]=(a[i+k]+t)%p; 61 w=w*wn%p; 62 } 63 } 64 } 65 if(!ops) 66 { 67 LL Inv=cheng(n,p-2); 68 for(int i=0;i<n;i++) 69 a[i]=a[i]*Inv%p; 70 } 71 } 72 73 int nn; 74 LL jc[N],ijc[N]; 75 LL f[N],ans; 76 77 int main() 78 { 79 jc[0]=jc[1]=1ll; 80 for(LL i=2;i<N;i++) 81 jc[i]=jc[i-1]*i%p; 82 for(LL i=0;i<N;i++) 83 ijc[i]=cheng(jc[i],p-2); 84 85 cin>>nn; 86 for(int i=1;i<=nn/2;i++) 87 f[i]=(ijc[i]*ijc[i]%p-ijc[i-1]*ijc[i+1]%p+p)%p; 88 f[0]=1ll; 89 90 init(nn*2); 91 ntt(f,1); 92 for(int i=0;i<n;i++) 93 f[i]=f[i]*f[i]%p; 94 ntt(f,0); 95 96 for(int i=0;i*2<=nn;i++) 97 ans=(ans+f[i]*jc[nn]%p*ijc[nn-2*i]%p)%p; 98 99 cout<<ans<<endl; 100 101 return 0; 102 }
**我们追究会相知,在那遥远的天穹。**