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 }

 

**我们追究会相知,在那遥远的天穹。**

posted @ 2017-09-14 16:58  KKiseki  阅读(92)  评论(0)    收藏  举报