2301: [HAOI2011]Problem b
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
1 5 1 5 2
Sample Output
14
3
思路 :
在我Zap的博客里有具体实现 2301就是相当于矩阵前缀和的那种处理, 把不满足条件的减掉就好辣!
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
const int N = 51000;
bool np[N];
int pr[N], tot, mu[N], sum[N];
using namespace std;
void init() {
mu[1]=1;
sum[1]=1;
for(int i=2;i<N;i++) {
if(!np[i]) {
pr[++tot]=i;
mu[i] = -1;
}
for(int j=1;j<=tot&&i*pr[j]<N;j++) {
np[i*pr[j]]=1;
if(i % pr[j] == 0) {
mu[i*pr[j]] = 0;
break;
}
mu[i*pr[j]]=-mu[i];
}
sum[i] = sum[i-1] + mu[i];
}
}
long long work(int a,int b,int d) {
a/=d;
b/=d;
if(a>b)swap(a,b);
int lst = 0;
long long ans=0;
for(int p=1;p<=a;p=lst+1) {
lst=min(a/(a/p),b/(b/p));
ans+=(long long)(sum[lst]-sum[p-1])*(a/p)*(b/p);
}
return ans;
}
int main() {
int t,a,b,c, d, k;
init();
//for(int i=1;i<=50000;i++) printf("%d\n",sum[i]);
scanf("%d",&t);
while(t--) {
scanf("%d%d%d%d%d",&a,&b,&c, &d, &k);
a--, c--;
long long ans1 = work(b,d,k);
ans1-= work(a, d, k);
ans1-= work(b, c, k);
ans1+= work(a, c, k);
printf("%lld\n", ans1);
}
}