2301: [HAOI2011]Problem b
Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 6493 Solved: 3013
[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、
1 #include<bits/stdc++.h> 2 #define N 50010 3 using namespace std; 4 int cnt,pri[N],vis[N],mo[N],sum[N]; 5 void predeal(){ 6 mo[1]=1; 7 for(int i=2;i<=5e4;i++){ 8 if(!vis[i]){mo[i]=-1;pri[++cnt]=i;} 9 for(int j=1;j<=cnt&&i*pri[j]<=5e4;j++){ 10 vis[i*pri[j]]=1; 11 if(i%pri[j]==0){mo[i*pri[j]]=0;break;} 12 else mo[i*pri[j]]=-mo[i]; 13 } 14 } 15 for(int i=1;i<=5e4;i++) 16 sum[i]=sum[i-1]+mo[i]; 17 } 18 int calc(int n,int m){ 19 if(n>m)swap(n,m); 20 int ret=0,i,pos=0; 21 while((i=pos+1)<=n){ 22 pos=min(n/(n/i),m/(m/i)); 23 ret+=(n/i)*(m/i)*(sum[pos]-sum[i-1]); 24 } 25 return ret; 26 } 27 int main(){ 28 int T;scanf("%d",&T);predeal(); 29 while(T--){ 30 static int a,b,c,d,k,ans; 31 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 32 --a;--c;a/=k;b/=k;c/=k;d/=k; 33 ans=calc(a,c)+calc(b,d)-calc(a,d)-calc(b,c); 34 printf("%d\n",ans); 35 } 36 return 0; 37 }