[FZYZOJ 1600] [NOIP福建夏令营]台阶问题

P1600 -- [NOIP福建夏令营]台阶问题

时间限制:1000MS

内存限制:131072KB

Description

有 N 级的台阶,你一开始在底部,每次可以向上迈最多 K 级台阶(最少 1 级),问到达第 N 级台阶有多少种不同方式。

Input Format

输入的仅包含两个正整数 N,K。

Output Format

输入仅包括 1 个正整数,为不同方式数,由于答案可能很大,你需要输出mod 100003 后的结果。

Sample Input

5 2

Sample Output

8

Hint

对于 20%的数据,有 N ≤ 10, K ≤ 3;

对于 40%的数据,有 N ≤ 1000;

对于 100%的数据,有 N ≤ 100000,K ≤ 100。

【题解】

首先,设f[i]为走到i的走法数量。

那么到i的方案一定是由(i-k)~(i-1)这之中的所有方案构成(因为这中间的每一级都可以一次跨到i这个台阶)

那么f[i]=sigma{f[i-j]} (0<=j<=k) f[0]=1;

那么我们有了第一份代码,实际上已经可以AC了。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int f[100001],n,k;
 4 int main() {
 5     scanf("%d%d",&n,&k);
 6     f[0]=1;
 7     for (int i=1;i<=n;++i) {
 8         for (int j=1;j<=i&&j<=k;++j)
 9             f[i]+=f[i-j], f[i]%=100003;
10         f[i]%=100003;
11     }
12     printf("%d
",f[n]);
13     return 0;
14 }
View Code

我们看到,时间复杂度为O(NK),10000000,还是可以过的。

我们发现,可以进行优化。

设一个变量sum表示前缀和进行优化,注意如果i>k的时候,我们需要的不是0...i的所有前缀和!

我们需要的只是部分的前缀和,所以要减去前面的,注意可能出现负数,加上后取模。

那么,f[i]=sum,sum=(sum+f[i]-f[i-k-1]+MOD)%MOD (i>k)  

那么,即可发现,时间复杂度优化到O(N)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 int f[100001],n,k,sum=0;
 4 int main() {
 5     scanf("%d%d",&n,&k);
 6     f[0]=1;
 7     for (int i=1;i<=n;++i) {
 8         if(i>k) {
 9             sum-=f[i-k-1];
10             sum=(sum+100003)%100003;
11         }
12         sum+=f[i-1];sum%=100003;
13         f[i]=sum;
14     }
15     printf("%d
",f[n]);
16     return 0;
17 }
View Code

这两份代码,在评测机上评测的时间分别为 0.358s和0.009s,说明优化也是非常重要的。

这篇文章由TonyFang发布。 所有解释权归TonyFang所有。 Mailto: tony-fang@map-le.net
原文地址:https://www.cnblogs.com/TonyNeal/p/fzyzoj1600.html