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

26 篇文章 0 订阅

题目描述

传送门

题目大意:
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 1000000007
using 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
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值