Jzoj3497 隐藏指令
题意:求在n维空间里,长度为2m且起点和终点重合的简单路径(只能在一维中走)数量
显然,我们在计算方案时,每次必然加入在同一维度的,方向相反的行动
那么我们令f[i][j][k]表示目前在处理第i维,已经走了2*j步,其中有2*k步在第i维上
那么显然,f[i+1][j][0]+=f[i][j][k] 这等于是停止当前这一维的处理,开始下一维
那么另一种转移是这样滴
f[i][j+1][k+1]+=f[i][j][k]*C(k+1<<1,k+1)/C(k<<1,k)*C(j+1<<1,k+1<<1)/C(j<<1,k<<1)
表示的是,在这一维加入一对相反的行动,那么,显然,在这一维里面,正反都是一样的
所以对于同一维中,若有2k步,我们有C(2k,k)排序方案,这点很显然因为这相当于在长度为2k的空格中插入k个0和k个1,那么方案自然是C(2k,k),那么我们先除去上一次的方案再乘上我们新加入的方案
而对于不同维度,互相不影响,所以相当于是把2k个对象放入长度为2j的数组中,那么这样的方案就有C(2j,2k)
所以f[i][j+1][k+1]+=f[i][j][k]*C(k+1<<1,k+1)/C(k<<1,k)*C(j+1<<1,k+1<<1)/C(j<<1,k<<1),先除去当前状态的影响再加入新的元素重新计算
而组合数乘除可以用逆元预处理,最后答案为Σf[d][n][k] (0<=k<=n)
#pragma GCC opitmize("O3") #pragma G++ opitmize("O3") #include<stdio.h> #include<string.h> #include<algorithm> #define L long long #define M 1000000007 using namespace std; inline L pow(L x,int k){ L s=1; for(;k;x=x*x%M,k>>=1) if(k&1) s=s*x%M; return s; } inline void ad(L& x,L y){ x=(x+y)%M; } L js[510],inv[510],A=0,f[210][210][210]; inline L C(int n,int m){ return js[n]*inv[m]%M*inv[n-m]%M; } inline L gC(int n,int m){ return inv[n]*js[m]%M*js[n-m]%M; } int main(){ *js=*inv=1; for(int i=1;i<=500;++i) js[i]=js[i-1]*i%M; inv[500]=pow(js[500],M-2); for(int i=500;i;--i) inv[i-1]=inv[i]*i%M; int n,d; scanf("%d%d",&d,&n); f[1][0][0]=1; for(int i=1;i<=d;++i) for(int j=0;j<=n;++j) for(int k=0;k<=j;++k) if(f[i][j][k]){ ad(f[i+1][j][0],f[i][j][k]); ad(f[i][j+1][k+1],f[i][j][k]*C(k+1<<1,k+1)%M*gC(k<<1,k)%M*C(j+1<<1,k+1<<1)%M*gC(j<<1,k<<1)%M); } for(int k=0;k<=n;++k) ad(A,f[d][n][k]); printf("%lld\n",A); }