「解题报告」P9157「GLR-R4」夏至
开学了,所以我要颓废了。
这题感觉好强,做法也好神奇。
首先我们考虑
发现这个函数满足
然后考虑
那么设
其中
记忆化一下,暴力跑这个东西即可。复杂度不会证,但是有效状态数大概
然后直接跑可能会 T 一个点,可以预处理出
这个做法很神奇啊,基本上没咋依赖
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000005, P = 1000000007, N = 1000000;
int n, k;
long long m;
struct Hash {
size_t operator()(const pair<int, long long> &p) const {
return ((p.first * 13331 + p.second) ^ (p.second >> 16 | ((long long) p.first) << 12)) % P;
}
};
unordered_map<pair<int, long long>, int, Hash> f;
int pri[MAXN], pcnt, mxp[MAXN], lp[MAXN], pc[MAXN];
bool vis[MAXN];
int qpow(int a, int b) {
int ans = 1;
while (b) {
if (b & 1) ans = 1ll * ans * a % P;
a = 1ll * a * a % P;
b >>= 1;
}
return ans;
}
int h[MAXN][88];
vector<pair<long long, int>> pn;
void dfs(long long x, int hx, int i) {
if (!hx) return;
pn.push_back({x, hx});
for (int j = i; j <= pcnt; j++) {
if (x > m / pri[j] / pri[j]) break;
long long t = x * pri[j] * pri[j];
for (int c = 2; t <= m; c++, t *= pri[j]) {
dfs(t, 1ll * hx * h[j][c] % P, j + 1);
}
}
}
int G(long long n) {
n %= P;
return 1ll * (n + 1) * n % P * ((P + 1) / 2) % P;
}
vector<int> ff[MAXN];
int fx[MAXN];
int F(int x, long long n) {
if (x * n <= N) {
return ff[x][n];
}
if (!n) return 0;
if (f.count({x, n})) return f[{x, n}];
if (x == 1) {
// PN 筛
int ans = 0;
for (auto p : pn) {
if (p.first > n) break;
ans = (ans + 1ll * p.second * G(n / p.first)) % P;
}
return f[{x, n}] = ans;
}
int p = mxp[x], x2 = lp[x];
long long m = n;
int ans = 0;
for (int i = 0; m; i++, m /= p) {
ans = (ans + 1ll * (F(x2, m) - F(x2 * p, m / p) + P) * qpow(p, __gcd(i + pc[x], k))) % P;
}
return f[{x, n}] = ans;
}
int main() {
scanf("%d%lld%d", &n, &m, &k);
fx[1] = 1;
for (int i = 2; i <= N; i++) {
if (!vis[i]) {
pri[++pcnt] = i;
mxp[i] = i;
lp[i] = 1;
pc[i] = 1;
}
for (int j = 1; j <= pcnt && i * pri[j] <= N; j++) {
vis[i * pri[j]] = 1;
mxp[i * pri[j]] = mxp[i];
lp[i * pri[j]] = pri[j] == mxp[i] ? lp[i] : lp[i] * pri[j];
pc[i * pri[j]] = pc[i] + (mxp[i] == pri[j]);
if (i % pri[j] == 0) {
break;
}
}
fx[i] = fx[lp[i]] * qpow(mxp[i], __gcd(pc[i], k));
}
ff[0] = vector<int>(N + 1, 0);
for (int i = 1; i <= N; i++) {
ff[i].push_back(0);
for (int j = 1; i * j <= N; j++) {
ff[i].push_back((ff[i][j - 1] + fx[i * j]) % P);
}
}
for (int i = 1; i <= pcnt; i++) {
h[i][0] = 1;
long long x = pri[i];
for (int j = 1; x <= m; j++, x *= pri[i]) {
h[i][j] = qpow(pri[i], __gcd(j, k));
int y = pri[i];
for (int k = 1; k <= j; k++, y = 1ll * y * pri[i] % P) {
h[i][j] = (h[i][j] - 1ll * h[i][j - k] * y % P + P) % P;
}
}
}
dfs(1, 1, 1);
sort(pn.begin(), pn.end());
int ans = 0;
for (int i = 1; i <= n; i++) {
ans = (ans + F(i, m)) % P;
}
printf("%d\n", ans);
return 0;
}
分类:
题解
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现