CF1558 B. Up the Strip
https://codeforces.com/problemset/problem/1558/B
题意:
n级台阶,求从第n级走到第1级的方案数
有2种走法
1、从n走到n-y y∈[1,n-1]
2、从n走到n/z z∈[2,n]
令f[i]表示从第i级走到第1级的方案数
f[i]= ∑ f[i-j] + ∑ f[i/k] j∈[1,i-1],k∈[2,i]
这是n^2的做法
前半部分就是一个前缀和,可以O(1)解决
后半部分可以用除法分块优化到O(n*sqrt(n))
思考后半部分能否利用类似于前缀或者后缀和优化的方式
设dp[i]表示从第n级走到第i级的方案数
枚举j,求哪些数除以j等于i, 发现是i*j到(i+1)*j-1的数除以j等于i,这就可以用后缀和优化一次求出这些数的贡献
i*j是i的倍数,相当于一共枚举了n以内所有数的倍数次,是nlogn的复杂度
#include<bits/stdc++.h> using namespace std; #define N 4000003 int f[N],dp[N]; int main() { int n,m,l,r; scanf("%d%d",&n,&m); dp[n]=f[n]=1; for(int i=n-1;i;--i) { dp[i]=f[i+1]; for(int j=2;j*i<=n;++j) { l=j*i; r=j*(i+1)-1; if(r>n) r=n; dp[i]=((dp[i]+f[l])%m-f[r+1]+m)%m; } f[i]=(f[i+1]+dp[i])%m; } printf("%d",dp[1]); }