題意
一句話題意不用再翻譯了吧。
思路
先考慮樸素的 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;
}