JZOJ【NOIP2013模拟联考14】隐藏指令

JZOJ【NOIP2013模拟联考14】隐藏指令

题目

Description

在d维欧几里得空间中,指令是一个长度为2N的串。串的每一个元素为d个正交基的方向及反方向之一。例如,d = 1时(数轴),串的每一个元素为左或右;d = 2时(平面),串的元素为上下左右之一;d = 3时(空间),串的元素为上下左右前后之一;d≥4时同理。
从起点出发,结月缘按照顺序一个一个的执行指令S中的元素,对于每个元素,结月往该方向行走1步。图2是一个例子,d = 2, S =→↓↑→→↓→→,|S|=2N=8。
在这里插入图片描述
我们认为,指令S是能够变得幸福的,当且仅当结月执行完该指令S后能够回到出发点。
请计算有多少种不同的指令S是能够变得幸福的,并输出其mod 1 000 000 007的值。两个指令被认为不同当且仅当存在一个位置,两个串在该处的元素不同。

Input

输入仅一行,两个用空格分开的非负整数d,N。

Output

输出仅一行,仅一个整数表示能够变得幸福的指令数mod 1 000 000 007。

Sample Input

输入1:
2 0
输入2:
2 1
输入3:
2 2
输入4:
3 1
输入5:
3 2

Sample Output

输出1:
1
【样例1说明】
空指令是能够变得幸福的。
输出2:
4
【样例2说明】
S1 =←→, S2 =→← , S3 =↑↓, S4 =↓↑
输出3:
36
【样例3说明】
如果结月缘只在一个维度上运动,也就是指令中横与纵的方向不同时出现,那么可能的情况有12种。如果结月缘在两个维度上都有运动,也就是指令中左右上下同时出现,那么有4! = 24种情况。相加后除以1 000 000 007取余数即可得到答案36。
输出4:
6
【样例4说明】
结月只能在三个维度之中一个运动,每个维度对应两种可能的能够变得幸福的隐藏指令。故总计3*2=6。
输出5:
90

Data Constraint

在这里插入图片描述

题解

题意

有一个 d d d维空间,同时有一个长度为 2 n 2n 2n的操作序列,每个操作往某一维的正方向或反方向走一格,问多少种方案使得最后走回原点,对 1 e 9 + 7 1e9+7 1e9+7取模

题解

5%

n = 0 n=0 n=0时答案是1
期望得分5

30%

d = 1 d=1 d=1时答案是 C 2 n n C_{2n}^n C2nn
因为只有正方向和反方向各占一半才能走回原点
综上,期望得分30

60%

d = 2 d=2 d=2时答案是 ( C 2 n n ) 2 (C_{2n}^n)^2 (C2nn)2
证明如下
在这里插入图片描述
综上,期望得分60

75%

d = 3 d=3 d=3时答案为
∑ i = 0 n ∑ j = 0 n − i C 2 n 2 i C 2 n − 2 i 2 j C 2 i i C 2 j j C 2 n − 2 i − 2 j n − i − j \sum_{i=0}^n\sum_{j=0}^{n-i}C_{2n}^{2i}C_{2n-2i}^{2j}C_{2i}^iC_{2j}^jC_{2n-2i-2j}^{n-i-j} i=0nj=0niC2n2iC2n2i2jC2iiC2jjC2n2i2jnij
证明同 d = 2 d=2 d=2
综上,期望得分75

100%

考虑 d p dp dp
f [ i ] [ j ] f[i][j] f[i][j]表示当前到了第 i i i维,放了 j j j对正反方向
转移
f [ i ] [ j ] = ∑ k = 0 j f [ i − 1 ] [ j − k ] ∗ C 2 j 2 k ∗ C 2 k k f[i][j]=\sum_{k=0}^jf[i-1][j-k]*C_{2j}^{2k}*C_{2k}^k f[i][j]=k=0jf[i1][jk]C2j2kC2kk
k k k表示当前这一维要放几对正反
预处理组合数即可

Code

#include<cstdio>
#include<cstring>
#define mod 1000000007
using namespace std;
int n,d,t[401];
long long s,now,g[401][401],f[401][401];
int main()
{
	scanf("%d%d",&d,&n);
	if (n==0)
	{
		printf("1\n");
		return 0;	
	} 
	g[0][0]=1;
	for (int i=1;i<=2*n;++i)
		for (int j=0;j<=i;++j)
			g[i][j]=(g[i-1][j-1]+g[i-1][j])%mod;
	f[0][0]=1;
	for (int i=1;i<=d;++i)
		for (int j=0;j<=n;++j) 
			for (int k=0;k<=j;++k)
				f[i][j]=(f[i][j]+((f[i-1][j-k]*g[2*j][2*k]%mod)*g[2*k][k]%mod))%mod;
	printf("%lld\n",f[d][n]);
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值