ζ

第十八届同济大学程序设计竞赛暨高校网络友谊赛C-困难的数学题

    题解

题目链接

问题可以抽象为在一个由n根棍子摆成的序列中插入若干个隔板,要求每个隔板间的棍子数量大于k,问有多少种放隔板的方法。

dp[x]为共有x根棍子时放隔板的方法。如果插入了隔板,第一块隔板的左边至少要有k个木棍,也可以有k+1、k+2…根,但是要保证它的右边的木棍数不少于k,也就是左边最多有n-k根木棍。

当第一根木棍左边有k、k+1、k+2…根木棍时,剩下的木棍的摆法分别为dp[x-k]dp[x-k-1]dp[x-k-2]…所以有

dp[x]=i=kxkdp[xi]dp[x]= \sum_{i=k}^{x-k}dp[x-i]

这么写可以求出正确答案,但是复杂度高得离谱(O(n!)O(n!))。

注意到

dp[x1]=i=kx1kdp[xi]dp[x-1]=\sum_{i=k}^{x-1-k}dp[x-i]

将它与上面写出的dp[x]dp[x]表达式做差,可以得到

dp[x]dp[x1]=dp[xk]dp[x]-dp[x-1]=dp[x-k]

dp[x]=dp[x1]+dp[xk]dp[x]=dp[x-1]+dp[x-k]

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cctype>
using namespace std;
const long long mod = 1e9 + 7;
long long dp[1000005];
int k;
long long dps(int x)
{
if (x < k)
return 0;
if (dp[x])
return dp[x];
return dp[x] = (dps(x - 1) + dps(x - k)) % mod;
}
int main()
{
int x;
scanf("%d%d", &x, &k);
dp[k] = 1;
printf("%lld", dps(x));
return 0;
}
页阅读量:  ・  站访问量:  ・  站访客数: