1. 程式人生 > 實用技巧 >求和「Dirichlet 字首和」

求和「Dirichlet 字首和」

題意及題解%%神仙gyz,NB就完了

然後,大佬好像沒給程式碼,蒟蒻給一份。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int maxn = 1e8 + 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;
int prime[maxn], tot, cnt[maxn], d[maxn];
int B[maxn];
bool vis[maxn];

void Pre() {
    memset(vis, 0, sizeof vis);
    cnt[1] = 1;
    d[1] = 1;
    for (int i = 2; i <= 50000000; i++) {
	if (!vis[i]) {
	    prime[++tot] = i;
	    d[i] = 1;
	    cnt[i] = 2;
	}
	for (int j = 1; j <= tot && i * prime[j] <= 50000000; 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);
    int n = read(), p = read();
    Pre();
    for (int i = 1; i <= tot && prime[i] <= n; i++) {
	for (int j = n / prime[i]; j; j--) {
	    cnt[j] += cnt[j * prime[i]];
	}
    }
    long long ans = 0;
    for (int i = 1; i <= n; i++) {
	ans += 1LL * cnt[i] * cnt[i];
	if (ans > p) ans %= p;
    }
    cout << ans << endl;
    return 0;
}

附一些乾貨:

線性求約數個數、約數和:https://blog.csdn.net/ControlBear/article/details/77527115?utm_source=blogxgwz24

Dirichlet 字首和:https://www.cnblogs.com/yijan/p/12356665.html