求和「Dirichlet 前缀和」
题意及题解:%%神仙gyz,NB就完了
然后,大佬好像没给代码,蒟蒻给一份。
Upd: 之前那个码跑得太慢了,而且内存好像超限了...
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 5e7 + 10;
inline int read() {
int s = 0, w = 1;
char c = getchar();
while (c < '0' || c > '9') { if (c == '-') w = -1; c = getchar(); }
while (c >= '0' && c <= '9') s = s * 10 + c - '0', c = getchar();
return s * w;
}
int n, p;
int prime[maxn / 10], tot, cnt[maxn], d[maxn];
bool vis[maxn];
void Pre() {
cnt[1] = 1;
d[1] = 1;
for (register int i = 2; i <= n; i++) {
if (!vis[i]) {
prime[++tot] = i;
d[i] = 1;
cnt[i] = 2;
}
for (register int j = 1; j <= tot && i * prime[j] <= n; j++) {
vis[i * prime[j]] = 1;
if (i % prime[j] == 0) {
d[i * prime[j]] = d[i] + 1;
cnt[i * prime[j]] = cnt[i] / (d[i] + 1) * (d[i] + 2);
break;
}
d[i * prime[j]] = 1;
cnt[i * prime[j]] = cnt[i] * 2;
}
}
}
int main() {
freopen("sum.in", "r", stdin);
freopen("sum.out", "w", stdout);
n = read(), p = read();
Pre();
for (register int i = 1; i <= tot && prime[i] <= n; i++) {
for (register int j = n / prime[i]; j; j--) {
cnt[j] += cnt[j * prime[i]];
}
}
long long ans = 0, sum = 0;
for (register int i = 1; i <= n; i++) {
ans += 1LL * cnt[i] * cnt[i];
if (ans > p) ans %= p;
}
printf("%lld\n", ans);
return 0;
}
附一些干货:
线性求约数个数、约数和:https://blog.csdn.net/ControlBear/article/details/77527115?utm_source=blogxgwz24
Dirichlet 前缀和:https://www.cnblogs.com/yijan/p/12356665.html
$$We're \; here \; to \; put \; a \; dent \; in \; the \; universe.$$