卧薪尝胆,厚积薄发。
qaq
Date: Sun Dec 23 15:57:46 CST 2018 In Category: NoCategory

Description:

一个 $k$ 维空间,刚开始在 $(0,0,\dots,0)$ ,每次随机往一个方向走一格,问随机走了 $n$ 步之后能经过的不同位置个数的期望,乘上 $2^k$ 的值 $\%p$ 的结果。
$1\leqslant n\leqslant 2000,1\leqslant k\leqslant 10$

Solution:

神奇的 $dp$ ,设 $f[i]$ 表示走的第 $i$ 步产生了一个新位置的概率,那么答案显然等于 $\sum f[i]$ ,然后转移就是枚举第一次走到这个位置的步数然后减掉对应的概率,也就是说先与处理一个 $circ[i]$ 表示经过 $i$ 步又回到了这个点的概率,这中间可以多次经过这个点,然后转移方程为: $$ f[i]=1-\sum_{j=1}^{\lfloor\frac i 2\rfloor}f[i-j\times 2]\times circ[j\times 2] $$ 然后这题就做完了。

Code:


#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cctype>
#include<cstring>
using namespace std;
int n,k,mod;
#define MAXN 2010
int C[MAXN][MAXN];
#define MAXK 12
int circ[MAXN][MAXK];
int f[MAXN],pows[MAXN];
int main()
{
scanf("%d%d%d",&n,&k,&mod);
C[0][0] = 1;
for(int i = 1;i <= n;++i)
{
C[i][i] = C[i][0] = 1;
for(int j = 1;j < i;++j)C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
for(int i = 0;i <= n;i += 2)circ[i][1] = C[i][i / 2];
for(int i = 2;i <= k;++i)
for(int x = 0;x <= n;x += 2)
for(int y = 0;y <= x;y += 2)
circ[x][i] = (circ[x][i] + 1ll * circ[x - y][i - 1] * circ[y][1] % mod * C[x][y] % mod) % mod;
pows[0] = 1;f[0] = 1;
for(int i = 1;i <= n;++i)
{
pows[i] = 1ll * pows[i - 1] * 2 * k % mod;
f[i] = pows[i];
for(int j = 1;j <= i / 2;++j)f[i] = (f[i] - 1ll * f[i - 2 * j] * circ[2 * j][k] % mod + mod) % mod;
}
int ans = 0;
for(int i = 0;i <= n;++i)ans = (ans + 1ll * f[i] * pows[n - i] % mod) % mod;
cout << ans << endl;
return 0;
}
Copyright © 2020 wjh15101051
ღゝ◡╹)ノ♡