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
",A);
}


原文地址:https://www.cnblogs.com/Extended-Ash/p/7774410.html