[BZOJ 2301] [HAOI2011] Problem b
2301: [HAOI2011]Problem b
Time Limit: 50 SecDescription
对于给出的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
3
HINT
100%的数据满足:1≤n≤50000,1≤a≤b≤50000,1≤c≤d≤50000,1≤k≤50000
【题解】莫比乌斯反演+前缀和处理即可。
分四段,然后容斥即可。
1 #include <cstdio> 2 #define min(x,y) x<y?x:y 3 using namespace std; 4 int mu[50010]; 5 bool chk[50010]; 6 int prime[50010],tot=0; 7 long long getsum(int x,int y) { 8 long long re=0; 9 int f=min(x,y),la; 10 for (int i=1;i<=f;i=la+1) { 11 la=min(x/(x/i),y/(y/i)); 12 re+=(long long)(x/i)*(y/i)*(mu[la]-mu[i-1]); 13 } 14 return re; 15 } 16 int main() { 17 //scanf("%d",&n); 18 mu[1]=1; 19 for (int i=2;i<=50000;++i) { 20 if (!chk[i]) { 21 prime[++tot]=i; 22 mu[i]=-1; 23 } 24 for (int j=1;j<=tot&&i*prime[j]<=50000;++j) { 25 chk[i*prime[j]]=1; 26 if(i%prime[j]==0) { 27 mu[i*prime[j]]=0; 28 break; 29 } 30 mu[i*prime[j]]=-mu[i]; 31 } 32 } 33 mu[0]=0; 34 for (int i=2;i<=50000;++i) mu[i]+=mu[i-1]; 35 int t; 36 scanf("%d",&t); 37 while(t--) { 38 int a,b,c,d,k; 39 scanf("%d%d%d%d%d",&a,&b,&c,&d,&k); 40 printf("%lld\n",getsum(b/k,d/k)-getsum((a-1)/k,d/k)-getsum(b/k,(c-1)/k)+getsum((a-1)/k,(c-1)/k)); 41 } 42 return 0; 43 }
这篇文章由TonyFang发布。
所有解释权归TonyFang所有。
Mailto: tony-fang@map-le.net