我发现kuangbin题单里的数论好像有点水,都是些线筛之类的
杜教筛
#include<bits/stdc++.h>
#include<unordered_map>
using namespace std;
template<typename T>void read(T& x) {
x = 0;
int p = 1;
char c = getchar();
while (!isdigit(c)) { if (c == '-')p = -1, c = getchar(); }
while (isdigit(c)) { x = (x << 1) + (x << 3) + (c - 48); c = getchar(); }
x *= p;
}
template<typename T>void write(T x) {
if (x < 0) putchar('-'), x = -x;
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
typedef long long ll;
const int maxn = 6e6 + 10;
int mu[maxn];
ll phi[maxn];
int sum_mu[maxn];
ll sum_phi[maxn];
int vis[maxn];
int prime[maxn], cnt;
unordered_map<int, ll>MU, PHI;
void get(int N) {
phi[1] = mu[1] = 1;
for (int i = 2; i <= N; i++) {
if (!vis[i]) {
prime[++cnt] = i;
mu[i] = -1;
phi[i] = i - 1;
}
for (int j = 1; j <= cnt && prime[j] * i <= N; j++) {
vis[prime[j] * i] = 1;
if (i % prime[j] == 0) {
phi[i * prime[j]] = phi[i] * prime[j];
break;
}
else {
mu[i * prime[j]] = mu[i] * -1;
phi[i * prime[j]] = phi[i] * (prime[j] - 1);
}
}
}
for (int i = 1; i <= N; i++) {
sum_phi[i] = sum_phi[i - 1] + phi[i];
sum_mu[i] = sum_mu[i - 1] + mu[i];
}
}
ll djs_mu(ll x) {
if (x <= maxn - 10)return sum_mu[x];
if (MU.count(x) != 0)return MU[x];
int ans = 1;
for (int l = 2, r;l <= x; l = r + 1) {
r = x / (x / l);
ans -= (r - l + 1) * djs_mu(x / l);
}
return MU[x] = ans;
}
ll djs_phi(ll x) {
if (x <= maxn - 10)return sum_phi[x];
if (PHI.count(x) != 0)return PHI[x];
ll ans = x * (x + 1) / 2;
for (ll l = 2, r; l <= x; l = r + 1) {
r = x / (x / l);
ans -= (r - l + 1) * djs_phi(x / l);
}
return PHI[x] = ans;
}
int main() {
int t, n;
read(t);
get(maxn - 10);
while (t--) {
read(n);
write(djs_phi(n)); putchar(' ');
write(djs_mu(n)); puts("");
}
}
莫比乌斯反演
一
[sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=1]
]
[ o sum_{i=1}^nsum_{j=1}^msum_{d|gcd(i,j)}mu(d)
]
[ o sum_{d=1}^nmu(d)*lfloor dfrac nd
floor * lfloor dfrac md
floor
]
分块搞就完事了
for (int l = 1, r; l <= min(n, m); l = r + 1) {
r = min(n / (n / l), m / (m / l));
ans += (n / l) * (m / l) * (sum[r] - sum[l - 1]);
}
二
[sum_{i=1}^nsum_{j=1}^m[gcd(i,j)=k]
]
[sum_{i=1}^{lfloor frac nk
floor}sum_{j=1}^{lfloor frac mk
floor}[gcd(i,j) = 1]
]
#include<bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 10;
int vis[maxn], prime[maxn], cnt, mu[maxn], sum[maxn];
void get_mu() {
mu[1] = 1;
for (int i = 2; i < maxn; i++) {
if (!vis[i]) {
prime[++cnt] = i;
mu[i] = -1;
}
for (int j = 1; j <= cnt && prime[j] * i < maxn; j++) {
vis[prime[j] * i] = 1;
if (i % prime[j] == 0) break;
mu[prime[j] * i] = mu[i] * -1;
}
}
for (int i = 1; i < maxn; i++) sum[i] = sum[i - 1] + mu[i];
}
int T, n, m, k;
int main() {
scanf("%d", &T);
get_mu();
while (T--) {
scanf("%d%d%d", &n, &m, &k);
n /= k; m /= k;
long long ans = 0;
for (int l = 1, r; l <= min(n, m); l = r + 1) {
r = min(n / (n / l), m / (m / l));
//这里没有加long long转换wa了一次
ans += 1ll* (n / l) * (m / l) * (sum[r] - sum[l - 1]);
}
printf("%lld
", ans);
}
}