[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\n",f[n]); 13 return 0; 14 }
我们看到,时间复杂度为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\n",f[n]); 16 return 0; 17 }
这两份代码,在评测机上评测的时间分别为 0.358s和0.009s,说明优化也是非常重要的。
这篇文章由TonyFang发布。
所有解释权归TonyFang所有。
Mailto: tony-fang@map-le.net