莫比乌斯反演
数论的东西总是好难QAQ,像我这样的蒟蒻心态崩溃
一个好的讲解:莫比乌斯反演
做了点题,莫比乌斯反演解决的就是快速计算函数的问题。
你有一个函数F(n)要算,但是特别难算,但是你有另一个函数f(n),F(n)能由f(n)相加求得,而且是倍数关系
这个时候就可以利用莫比乌斯反演函数简化运算
还需要强大的数学运算水平QAQ
上题:
2301: [HAOI2011]Problem b
Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 6139 Solved: 2803
[Submit][Status][Discuss]
Description
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
Input
第一行一个整数n,接下来n行每行五个整数,分别表示a、b、c、d、k
Output
共n行,每行一个整数表示满足要求的数对(x,y)的个数
Sample Input
2
2 5 1 5 1
1 5 1 5 2
2 5 1 5 1
1 5 1 5 2
Sample Output
14
3
HINT
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
了解莫比乌斯反演函数后很快就能看出,一道莫比乌斯反演的入手题
但是需要简化运算【还不会用编辑器时间紧就不写式子了,上面的链接讲的很清楚】
要注意的是通常遇到n / d这样的整除运算都是可以分块计算的
这题中用到的是满足(n / d) = (n / i)的最大的d = n / (n / i)
还用到了容斥原理
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<bitset>
#define LL long long int
#define REP(i,n) for (int i = 1; i <= (n); i++)
#define fo(i,x,y) for (int i = (x); i <= (y); i++)
#define Redge(u) for (int k = head[u]; k != -1; k = edge[k].next)
using namespace std;
const int maxn = 50005,maxm = 100005,INF = 1000000000;
int miu[maxn],prime[maxn],primei = 0,sum[maxn];
bitset<maxn> isn;
inline int read(){
int out = 0,flag = 1;char c = getchar();
while (c < 48 || c > 57) {if (c == '-') flag = -1; c = getchar();}
while (c >= 48 && c <= 57) {out = out * 10 + c - 48; c = getchar();}
return out * flag;
}
void init(){
isn.set();
miu[1] = 1;
for (int i = 2; i < maxn; i++){
if (isn[i]) prime[++primei] = i,miu[i] = -1;
for (int j = 1; j <= primei && i * prime[j] < maxn; j++){
isn[i * prime[j]] = false;
if (i % prime[j] == 0){ miu[i * prime[j]] = 0; break; }
miu[i * prime[j]] = -miu[i];
}
}
for (int i = 1; i < maxn; i++) sum[i] = sum[i - 1] + miu[i];
}
int cal(int n,int m){
if (n > m) swap(n,m);
int ans = 0,nxt;
for (int i = 1; i <= n; i = nxt + 1){
nxt = min(n / (n / i),m / (m / i));
ans += (sum[nxt] - sum[i - 1]) * (n / i) * (m / i);
}
return ans;
}
int main()
{
init();
int N,a,b,c,d,k;
N = read();
while (N--){
a = read(); b = read(); c = read(); d = read(); k = read();
a--; c--;
a/=k;b/=k;c/=k;d/=k;
printf("%d\n",cal(b,d) - cal(b,c) - cal(a,d) + cal(a,c));
}
return 0;
}

浙公网安备 33010602011771号