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 }
View Code

 

posted @ 2013-10-04 16:52  Yours1103  阅读(273)  评论(0编辑  收藏  举报