杭电多校第七场(求gcd(a,b)的个数,a,b范围限制1~n,1~m)

GuGuFishtion

Time Limit: 3000/1500 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1149    Accepted Submission(s): 432

Problem Description

Today XianYu is too busy with his homework, but the boring GuGu is still disturbing him!!!!!!
At the break time, an evil idea arises in XianYu's mind.
‘Come on, you xxxxxxx little guy.’
‘I will give you a function ϕ(x) which counts the positive integers up to x that are relatively prime to x .’
‘And now I give you a fishtion, which named GuGu Fishtion, in memory of a great guy named XianYu and a disturbing and pitiful guy GuGu who will be cooked without solving my problem in 5 hours.’
‘The given fishtion is defined as follow:

Gu(a,b)=ϕ(ab)ϕ(a)ϕ(b)

And now you, the xxxxxxx little guy, have to solve the problem below given m ,n ,p .’

(∑a=1m∑b=1nGu(a,b))(modp)

So SMART and KINDHEARTED you are, so could you please help GuGu to solve this problem?
‘GU GU!’ GuGu thanks.
 

Input

Input contains an integer T indicating the number of cases, followed by T lines. Each line contains three integers m ,n ,p as described above.
1≤T≤3
1≤m,n≤1,000,000
max(m,n) And given p is a prime.

 

Output

Please output exactly T lines and each line contains only one integer representing the answer.

Sample Input

1 5 7 23

Sample Output

2

 

Source

2018 Multi-University Training Contest 7

 

Recommend

chendu   |   We have carefully selected several similar problems for you:  6396 6395 6394 6393 6392 

 

Statistic | Submit | Discuss | Note

【题意】

给出函数G(a,b)= F[a*b] / (F[a]*F[b]);其中F是欧拉函数

求sum( G(a,b) )%p;其中  1<=a<=m, 1<=b<=n;

【分析】

欧拉函数有这样一个重要性质:F[a*b]=F[a]*F[b]*d/F[d];  其中d=gcd(a,b);

故:G(a,b) = d/F[d]; 问题就变成了统计一下每一个d的个数。

枚举d,每一个d的个数可提前通过线性筛算出来,这是一个本菜鸡新学的骚操作。

列一个表格,n行m列,每个元素就填gcd(i,j)。会发现,对于d来说,它只出现在第d行和第d列,而且有的会被d的倍数覆盖。

所有第d行第d列的个数就是(n/d)*(m/d),然后减掉他的倍数覆盖掉的位置个数,这个个数早就算出来了呀。详见函数count_gcd(ll n,ll m);

【代码】

/****
***author: winter2121
****/
#include
#define rep(i,s,t) for(int i=s;i<=t;i++)
#define SI(i) scanf("%d",&i)
#define PI(i) printf("%d\n",i)
using namespace std;
typedef long long ll;
const int MAX=2e5+5;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
int dir[9][2]={0,1,0,-1,1,0,-1,0, -1,-1,-1,1,1,-1,1,1};
templatebool gmax(T &a,T b){return abool gmin(T &a,T b){return a>b?a=b,1:0;}

ll gcd(ll a,ll b){ while(b) b^=a^=b^=a%=b; return a;}
ll inv(ll b,ll mod){return b==1?1:(mod-mod/b)*inv(mod%b,mod)%mod;}

int phi[1001010],M=1000010;
void phi_table(){
    memset(phi,0,sizeof(phi));
    phi[1]=1;
    for(int i=2;i<=M;i++) if(!phi[i]){
        for(int j=i;j<=M;j+=i){
            if(!phi[j]) phi[j]=j;
            phi[j]=phi[j]/i*(i-1);
        }
    }
}

ll fac[1000010]; //(a<=n,b<=m)范围内gcd=i的个数(筛选:i的倍数都应该减掉)
void count_gcd(ll n,ll m) //gcd(a,b)的个数(a<=n,b<=m)
{
    ll nm=min(n,m);
    for(int i=nm;i>=1;i--) //枚举gcd
    {
        fac[i]=(n/i)*(m/i); //n,m内i的倍数出现次数
        for(int j=i+i;j<=nm;j+=i) //两倍及以上的都要去掉
            fac[i]-=fac[j];
    }
}

ll INV[1000010];
int main()
{
    phi_table();
    int n,m,p,T;
    cin>>T;
    while(T--)
    {
        scanf("%d%d%d",&m,&n,&p);
        if(m>n)swap(n,m);
        count_gcd(m,n);
        INV[1]=1;
        for(int i=2;i<=m;i++)INV[i]=(p-p/i)*INV[p%i]%p;
        ll ans=0;
        for(int i=1;i<=m;i++)
        {
            ans+=fac[i]%p*i%p*INV[phi[i]]%p;
            ans%=p;
        }
        printf("%lld\n",ans);
    }
    return 0;
}

 

你可能感兴趣的:(ACM**数论*******)