設 表示 位置填 滿足條件的方案數, 則 , 直接轉移複雜度 , 不可過 .
觀察到 的取值僅有 個, 且轉移是前綴和的形式, 因此考慮使用 整除分塊 和 前綴和 優化,
設 表示 位置填 整除分塊 從大到小 第 種 值所對應的 分母 的方案數, 表示 對應 前綴和, 則
最後 , 使用 std::map<int, int>
時間複雜度 .
爲取值的總個數, 整除分塊的值從前往後單調不增 : M M-1 M-1 M-2 M-2 M-2 …
爲 對應的塊的編號 .
表示編號爲 的塊對應的值 .
但是 直接使用 std::map<int,int>
儲存會 ,
觀察到在 從小到大 枚舉 時, 的值是 單調不增 的, 且只會變化 次, 因此可以使用指針維護 .
時間複雜度 .
#include<bits/stdc++.h>
#define reg register
const int maxn = 1000005;
const int mod = 1e9 + 7;
int N;
int M;
int cnt;
int Mp[maxn];
int val[maxn];
int llim[maxn];
int rlim[maxn];
int F[102][maxn];
int g[102][maxn];
int main(){
scanf("%d%d", &N, &M);
for(reg int l = 1, r; l <= M; l = r+1){
r = M/(M/l), llim[++ cnt] = l, rlim[cnt] = r;
F[1][cnt] = r-l+1, val[cnt] = M/l;
g[1][cnt] = (g[1][cnt-1] + F[1][cnt]) % mod;
}
for(reg int i = 2; i <= N; i ++){
int t = cnt;
for(reg int j = 1; j <= cnt; j ++){
while(t >= 1 && M/(M/llim[j]) > val[t]) t --;
F[i][j] = (rlim[j]-llim[j]+1)*1ll*g[i-1][t] % mod;
g[i][j] = (g[i][j-1] + F[i][j]) % mod;
}
}
printf("%d\n", g[N][cnt]);
return 0;
}