csu 10月 月赛 H 题 A Very Hard Problem
Description
CX老湿经常被人黑,被黑得多了,自己也就麻木了。于是经常听到有人黑他,他都会深情地说一句:禽兽啊!
一天CX老湿突发奇想,给大家出了一个难题,并且声称谁能够准确地回答出问题才能继续黑他,否则他就要反击了。
这个难题就是:
给出两个数p和q,接下来q个询问,每个询问给出两个数A和B,请分别求出:
一、有多少个有序数对(x,y)满足1<=x<=A,1<=y<=B,并且gcd(x,y)为p的一个约数;
二、有多少个有序数对(x,y)满足1<=x<=A,1<=y<=B,并且gcd(x,y)为p的一个倍数。
Input
只有一组测试数据。
第一行两个数:p和q。(1<p<10^7 ,1<q<1000。)
接下来有q行,每行两个数A和B。(1<A,B<10^7)
Output
输出共q行。每行两个数。用空格隔开。
分别表示题目描述中的两个对应的答案。
(x,y)=(2,3)和(x,y)=(3,2)被视为两个不同有序数对哦!
Sample Input
6 3 8 8 15 32 13 77
Sample Output
58 1 423 10 883 24
HINT
对于64位整型请用lld,或者cin,cout。T_T
CSU_LQ
Source
题解:
1.对于第二个答案,就是(a/p)*(b/p);
2.对于第一个答案,要用到莫比乌斯函数,比如如统计gcd(x,y)=3的情况,(假设p=10),将会有3,6,9这三种情况,如果算(10/3)*(10/3)的话将会有重复计算的;
如果在上面乘以莫比乌斯系数的话就不会了,他们的系数分别为 1,-1,-1,则结果就是:1*(10/3)*(10/3)-1*(10/6)*(10/6)-1*(10/9)*(10/9);
所以要对莫比乌斯系数打表,比赛的时候,一个大神用一个神码A了这个题;无比的膜拜!!!OTL
分享一个:
1 #include<cstdio> 2 #define maxn 10000001 3 #define ll long long 4 using namespace std; 5 int a,b,cnt[maxn]; 6 ll getans(int l,int r) 7 { 8 if(l>r)return 0; 9 if(a/l==a/r&&b/l==b/r) 10 return (ll)(cnt[r]-cnt[l-1])*(a/l)*(b/l); 11 return getans(l,(l+r)/2)+getans((l+r)/2+1,r); 12 } 13 14 int main() 15 { 16 int p,q; 17 scanf("%d%d",&p,&q); 18 for(int i=1;i<maxn;i++) 19 { 20 if(p%i==0)cnt[i]++; 21 if(cnt[i]!=0)for(int j=i+i;j<maxn;j+=i) 22 cnt[j]-=cnt[i]; 23 cnt[i]+=cnt[i-1]; 24 } 25 while(q--) 26 { 27 scanf("%d%d",&a,&b); 28 printf("%lld %d\n",getans(1,maxn-1),(a/p)*(b/p)); 29 } 30 return 0; 31 }