http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=1208
n天的课程,如果连续超过m个就会发生爆炸,问你不会发生爆炸的情况。
以前写的时候以为这是一个排列问题,后来看了好多已经确定这是一个DP了。
开始想用递推写,没有递推好,
思路:dp[i][j],i为截止到当前的天数,考试天数达到j的次数。
这样就可以发现两个递推方程。
1 第i天天数达到0的天数等于所有 dp[i-1][j]的累加。(第i天没有考试)
2 第i天天数达到j的天数等于 所有dp[i-j][0]的情况,(i-j到i的情况都是固定的,一定考试。但i-j这一天不考试,第i天考试)。
至少为1天。(如果是0天的话,在第一个已经包括了)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
/*这是一个计数的dp,这种东西如果没有思路的话很容易想成
其他算法,比方说排列组合之类的。
其实是一个计数的dp
分为两种,当当前数为0时候。所有的结果等于之前的相加。
当当前不为0时,等于前面出现j个连续的相加。
(我其实还是不太懂这个东西,)
题目最大是50,所以要用long,long
*/
using namespace std;
long long dp[105][10];
int main(){
long long n,m,i,j,ans;
//freopen("boom.in","r",stdin);
//freopen("boom.out","w",stdout);
//cout<<(long long )pow(2,50)<<endl;
while(~scanf("%lld%lld",&n,&m))
{ memset(dp,0,sizeof(dp));
dp[0][0]=1;//什么都不存在也是1
for( i=1;i<=n;i++)
{ for( j=0;j<m;j++)
dp[i][0]+=dp[i-1][j];
for( j=1;j<=min(i,m-1);j++)
dp[i][j]+=dp[i-j][0];
}
ans=0;
for( i=0;i<m;i++)
ans+=dp[n][i];
cout<<ans<<endl;
}
return 0;
}