[ABC132F] Small Products 題解

PerchLootie發表於2024-08-21

題意

一句話題意不用再翻譯了吧。

思路

先考慮樸素的 dp,設 \(dp_{i,j}\) 表示長度為 \(i\) 結尾數字為 \(j\) 的序列的方案數,狀態很好轉移:

\[dp_{i,j}=\sum_{a=1}^{\lfloor \frac{N}{j} \rfloor}dp_{i-1,a} \]

這樣時間複雜度是 \(\Theta(nk)\) 的,顯然過不了。

考慮最佳化這個 dp
我們發現 \(\lfloor \frac{N}{j} \rfloor\) 在一段區間內的值是一樣的,自然想到整除分塊。
我們預處理出每一塊的 \(\lfloor \frac{N}{j} \rfloor\)\(m_i\)、長度 \(len_i\) 和塊的個數 \(cnt\),這時的狀態轉移如下:

\[dp_{i,j}=\sum_{j=1}^{cnt}dp_{i,j-1}+dp_{i-1,cnt-j+1}\times len_{j} \]

這裡狀態中的 \(j\) 表示第 \(j\) 塊。

時間複雜度 \(\Theta(\sqrt{n}k)\)

#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int n,m;
int dp[105][100005];
int a[100005],len[100005],cnt;
signed main(){
    scanf("%lld%lld",&n,&m);
    for(int l=1,r;l<=n;l=r+1){
        r=(n/(n/l));
        a[++cnt]=r;
        len[cnt]=r-l+1;
    }
    for(int i=1;i<=cnt;i++) dp[0][i]=1;
    for(int i=1;i<=m;i++){
        int d=cnt;
        for(int j=1;j<=cnt;j++){
            dp[i][j]=(dp[i][j-1]+len[j]*dp[i-1][d--]%mod)%mod;
        }
    }
    printf("%lld",dp[m][cnt]);
    return 0;
}

相關文章