BZOJ2301——莫比乌斯&&整除分块
题目
对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数。
分析
莫比乌斯经典入门题。
(我也刚学,就写一下
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 50000 + 10; int mu[maxn], prime[maxn], tot; //莫比乌斯表、素数表,素数个数 bool vis[maxn]; int premu[maxn]; //莫比乌斯的前缀和 void getMu(int n) { mu[1]=1; for(int i = 2;i <= n;i++) { if(!vis[i]) prime[++tot] = i, mu[i] = -1; for(int j = 1;j <= tot && (ll)i * prime[j] <= n;j++) { vis[i * prime[j]] = true; if(i % prime[j] == 0) { mu[i * prime[j]] = 0; break; } mu[i * prime[j]] = -mu[i]; } } for(int i = 1;i <= n;i++) premu[i] = premu[i-1] + mu[i]; } //1≤i≤n, 1≤j≤m, \sigma[gcd(i,j)=1] int solve(int n, int m) { int res=0; for(int i=1,j;i <= min(n,m);i = j+1) { j = min(n/(n/i), m/(m/i)); res += (premu[j]-premu[i-1]) * (n/i) * (m/i); } return res; } int a, b, c, d, k; int main() { getMu(maxn); int T; scanf("%d", &T); while(T--) { scanf("%d%d%d%d%d", &a, &b, &c, &d, &k); printf("%d\n", solve(b/k, d/k) - solve((a-1)/k, d/k) - solve(b/k, (c-1)/k) + solve((a-1)/k, (c-1)/k)); } return 0; }
个性签名:时间会解决一切