题目链接:https://ac.nowcoder.com/acm/contest/9680/E
由定义式可以发现,如果 (k > log(n)),那么答案就一定是 (0), 所以我们只需要计算 (k <= 27) 的答案即可
记忆化搜索,使用 (unordered_map) 存储 (dp) 数组的答案
对于每个块,如果左端点为 (l), 那么对于 (log(i)), 右端点 (r1 = 1 << log(i)), 对于 (frac{n}{i}),右端点为 (r2 = frac{n}{frac{n}{l}})
每次分块的右端点 (r) 取 (r = min(r1, r2)) 即可,具体实现参考代码
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<unordered_map>
using namespace std;
typedef long long ll;
const int M = 1000000007;
int n, k;
unordered_map<int, int> dp[30];
int dfs(int N, int K){
if(K == 0){
return dp[K][N] = 1;
}
if(dp[K].find(N) != dp[K].end()){
return dp[K][N];
}
int res = 0;
int l, r;
int kk = 0;
for(l = 2 ; l <= N ;){
while(1 << (kk + 1) < l) ++kk;
if((1 << kk) < l) ++kk;
r = min(min(N / (N / l), (1 << kk)), N);
res = (res + 1ll * (r - l + 1) * kk % M * dfs(N / l, K - 1) % M) % M;
l = r + 1;
}
return dp[K][N] = res;
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
n = read(), k = read();
if(k >= 27) printf("0
");
else {
printf("%d
", dfs(n, k));
}
return 0;
}