数论的东西总是好难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 ",cal(b,d) - cal(b,c) - cal(a,d) + cal(a,c)); } return 0; }