求和「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

posted @ 2020-09-17 20:18  zfio  阅读(132)  评论(0编辑  收藏  举报