码农的生活:朴实无华,且枯燥。
我的题解:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int MOD=100003;
int main()
{
int n,k;
cin>>n>>k;
int arr[100005];
memset(arr,0,sizeof(arr));
arr[1]=1;
for(int i=2;i<=k;i++)
{
for(int j=1;j<i;j++)
{
arr[i]+=arr[i-j];
if(arr[i]>MOD) arr[i]%=MOD;
}
arr[i]+=1;
if(arr[i]>MOD) arr[i]%=MOD;
}
for(int i=k+1;i<=n;i++)
{
for(int j=1;j<=k;j++)
{
arr[i]+=arr[i-j];
if(arr[i]>MOD) arr[i]%=MOD;
}
}
cout<<arr[n]<<endl;
return 0;
}
转的题解:
深搜超时,于是想到DP...
虽说是递推,但是从思想上来说我更倾向于动态规划的理解方式,因为我就是这么理解的。
定义状态f[i]:走i步台阶的方案总数;
递推公式:f[i]=sigma( j← 1 to min(i,k)) f[i-j]; j的意义是第一步先迈j个阶梯,j<=k是题意要求,j<=i因为j>i没有意义,所以j<=min(i,k);
分析状态转移公式,可以发现对于i来说,在不考虑方案对称性的前提下(也就是题目的要求,先迈一步再迈十步与先迈十步再迈一步是两个不同的方案),对于不同的j方案在一开始就不同了,所以在求和计算f[i']时因为每次i不存在重复计算的问题。
目标状态f[n],起点状态是f[1],显然f[1]=1;
初始化f[0]=1则是在后面递推的时候写着方便,f[0]的意义在于,由于我们枚举了j=min(i,k),即可能存在i==j的情况,具体意义为一步迈到终点(条件为i<=k),这一步是合法方案,所以令f[0]=1让计算一般化;
代码很短:
#include<iostream>
using namespace std;
int n,k;
int main(){
cin>>n>>k;
int f[n+1];
for(int i=2;i<=n;i++) f[i]=0;
f[1]=f[0]=1;
for(int i=2;i<=n;i++){
for(int j=min(i,k);j>=1;j--){
f[i]+=f[i-j];
if(f[i]>=100003) f[i]%=100003; //注意取模!!!卡了我一次
}
}
cout<<f[n];
return 0;
}