设 表示 位置填 满足条件的方案数, 则 , 直接转移复杂度 , 不可过 .
观察到 的取值仅有 个, 且转移是前缀和的形式, 因此考虑使用 整除分块 和 前缀和 优化,
设 表示 位置填 整除分块 从大到小 第 种 值所对应的 分母 的方案数, 表示 对应 前缀和, 则
最后 , 使用 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
", g[N][cnt]);
return 0;
}