台阶问题

分析
D f s n 1 e 5 O 2 n 第一眼看到这题的时候就直接想用Dfs模拟走路的过程,可是发现n数据范围为1e5,就计算一下复杂度。接近O(2^n) Dfsn1e5O2n
t l e d f s T l e d f s 无非就是tle。但是为了练习我的dfs模板,于是我就手打一遍Tle的dfs,代码如下 tledfsTledfs

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
ll cnt=0,n,k,p=100003;
void dfs(ll num){
	if(num==n) {cnt++;cnt=cnt%p;return ;}
	if(num>n) return ;
	for(int i=1;i<=k;i++){
		dfs(num+i);
	}
	return;
}
int main(){
    scanf("%lld%lld",&n,&k);
    dfs(0);
    cout<<cnt<<endl;
    return 0;
}
///dfs的复杂度是2^n tle

d f s d p d p 接下来,我就想用什么来优化dfs呢?dp突然出现在我的脑海里面,分析一波dp可用性,发现符合最小子问题 dfsdpdp
j , i d p [ d i s ] d i s 于是,我就假设初始位置为j,目标位置为i,那么dp[dis]表示走到dis的时候所用的所有可能方式。我们接下来考虑 j,idp[dis]dis
j i 怎样从j转移到i位置呢? ji
j i j = i k , i ( k 1 ) , i ( k 2 ) , . . . . . . , i 1 d p [ i ] 从j位置走到i位置,分j=i-k,i-(k-1),i-(k-2),......,i-1这些位置走一步到达,那么我们就可以利用循环来更新dp[i] jij=ik,i(k1),i(k2),......,i1dp[i]

for(int i=1;i<=n;i++){
    for(int j=1;j<=k;j++){/判断条件需要修改,这里只是为了说明怎么走
        dp[i]=dp[i]+dp[i-j];
    }
}

i k 细心的你可以发现当i小与等于k的时候会出现错误。没错,就是这样,这里我们就可以在上面的判断条件中改一下 ik
j &lt; = k 把j&lt;=k j<=k改成j<=k&&i-j>=0

AC

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=1e5+5;
int n,k,p=100003,dp[maxn];
int main(){
    scanf("%d%d",&n,&k);
    dp[0]=dp[1]=1;
    for(int i=2;i<=n;i++){
    for(int j=1;j<=k&&i-j>=0;j++){
        dp[i]=(dp[i]+dp[i-j])%p;
    }
    }
    cout<<dp[n]<<endl;
    return 0;
}


备注,ll数据处理比int数据慢很多,见下图