hdu 5780 gcd(线性筛+快速幂+数论)

来源:互联网 发布:华数网络 编辑:程序博客网 时间:2024/05/06 18:04

题目描述

传送门

题目大意:
1<=a,b<=ngcd(xa1,xb1)

题解

首先对于gcd(xa1,xb1)进行化简
更相减损gcd(a,b)=gcd(ab,b)
那么gcd(xa1,xb1)=gcd(xaxb,xb1)=gcd(xb(xab1),xb1)
又因为xb,xb1 互质,所以
gcd(xa1,xb1)=gcd(xab1,xb1)
gcd(xa1,xb1)=xgcd(a,b)1

那么原始的式子就变成了1<=a,b<=nxgcd(a,b)1

k=1n(xk1)i=1nj=1n[gcd(i,j)=k]

k=1n(xk1)i=1nkj=1nk[gcd(i,j)=1]

因为[n=1]=d|nμ(d),所以
k=1n(xk1)i=1nkj=1nkd|gcd(i,j)μ(d)

k=1n(xk1)d=1nki=1nk[d|i]j=1nk[d|j]μ(d)

k=1n(xk1)d=1nknkd2μ(d)

这样可以O(Tn34) 利用分块求解,但是如何继续优化呢?
考虑对于F[m]=mi=1mj=1[gcd(i,j)=1] 进行更直观的理解
F[m]=2(a=1mb=1a[gcd(a,b)=1])1

F[m]=2(a=1mϕ(a))1

对于(xk1)这一部分,我们对于每一块讲将所有的-1提出来,然后利用等比数列求和公式计算即可。

代码

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define LL long long #define N 1000003#define p 1000000007using namespace std;int n,T,prime[N],pd[N],mu[N],SUM[N];LL a[N],x,ans,smu[N],phi[N];LL gcd(LL x,LL y){    LL r;    while (y) {        r=x%y;        x=y; y=r;    }     return x;}void init(){    mu[1]=1; phi[1]=1;    for (int i=2;i<=1000000;i++) {        if (!pd[i]) {            prime[++prime[0]]=i;            mu[i]=-1; phi[i]=i-1;        }        for (int j=1;j<=prime[0];j++) {            if (i*prime[j]>1000000) break;            pd[i*prime[j]]=1;            if (i%prime[j]==0) {                mu[i*prime[j]]=0;                phi[i*prime[j]]=phi[i]*prime[j];                break;            }            else {                mu[i*prime[j]]=-mu[i];                phi[i*prime[j]]=phi[i]*(prime[j]-1);            }        }    }    for (int i=1;i<=1000000;i++) phi[i]=(phi[i]+phi[i-1])%p;}LL quickpow(LL num,int x){    LL ans=1; LL base=num%p;    while (x) {        if (x&1) ans=ans*base%p;        x>>=1;        base=base*base%p;    }    return ans;}int main(){    scanf("%d",&T);    init();    while (T--) {        scanf("%I64d%d",&x,&n);        ans=0; int j=0;        for (int i=1;i<=n;i=j+1) {            j=min(n/(n/i),n);            LL t=2*phi[n/i]-1; t%=p;              LL a1=quickpow(x,i); LL q=quickpow(x,(j-i+1));            LL t1=a1*(q-1)%p*quickpow(x-1,p-2)%p-(j-i+1);            //cout<<t<<" "<<t1<<endl;            ans=(ans+t*t1%p)%p;        }        if (x==1) printf("0\n");        else  printf("%I64d\n",(ans%p+p)%p);    }}
0 0
原创粉丝点击