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]); 
}

 

posted @ 2021-09-07 21:45  TRTTG  阅读(70)  评论(0编辑  收藏  举报