原题地址:http://codeforces.com/gym/101982
参考博客:https://blog.csdn.net/jk_chen_acmer/article/details/82016719
这篇博客主要是讲述一些莫比乌斯的知识。
关于莫比乌斯函数
莫比乌斯函数其实就只是一个系数,它的取值如下:
1)莫比乌斯函数μ(n)的定义域是N
2) μ ( 1 ) = 1 μ(1)=1 μ(1)=1
3)当 n n n存在平方因子时, μ ( n ) = 0 μ(n)=0 μ(n)=0
4)当 n n n是素数或奇数个不同素数之积时, μ ( n ) = − 1 μ(n)=-1 μ(n)=−1
5)当 n n n是偶数个不同素数之积时, μ ( n ) = 1 μ(n)=1 μ(n)=1
关于莫比乌斯反演
主要有两种形式:
上面的被称为约数反演,下面的被称为倍数反演。
作用:它是两个函数互相转换时的一大利器。
所以在某些情况下当 f ( d ) f(d) f(d)不好处理而 F ( n ) F(n) F(n)比较好求时可以考虑求出 F ( n ) F(n) F(n)的值再反演给 f ( d ) f(d) f(d)。
对于这道题
具体参考上面的参考链接。
#include
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)+1
#define CLR(x,y) memset((x),y,sizeof(x))
#define fuck(x) cerr << #x << "=" << x << endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int seed = 131;
const int maxn = 1e7 + 5;
const int mod = 1e9 + 7;
bool isprime[maxn];
int prime[maxn];
int sum[maxn], mu[maxn];
int pcnt;
void mobi(int N) {
memset(isprime, true, sizeof(isprime));
mu[1] = 1;
for (int i = 2; i < N; i++) {
if (isprime[i]) {
prime[++pcnt] = i;
mu[i] = -1;
}
for (int j = 1; i * prime[j] < N; j++) {
isprime[i * prime[j]] = false;
if (i % prime[j] == 0) {
mu[i * prime[j]] = 0;
break;
} else mu[i * prime[j]] = -mu[i];
}
}
for (int i = 1; i < N; i++) {
//前缀和预处理
sum[i] = mu[i] + sum[i - 1];
}
}
ll a, b, c, d;
ll solve(ll n, ll m) {
if (n > m) swap(n, m);
ll ans = 0;
for (ll i = 1, last; i <= n; i = last + 1) {
//处理了前缀和之后分块处理
last = min(n / (n / i), m / (m / i));
ans += (sum[last] - sum[i - 1]) * (n / i) * (m / i);
}
return ans;
}
int main() {
mobi(1e7 + 1);
scanf("%lld%lld%lld%lld", &a, &b, &c, &d);
ll ans = solve(b, d) - solve(a - 1, d) - solve(b, c - 1) + solve(a - 1, c - 1);//像二维前缀和一样容斥
printf("%lld\n", ans);
return 0;
}