hdu 5780 gcd

首先是一个公式:

gcd(a^m-b^m,a^n-b^n)=a^(gcd(m,n))-b^(gcd(m,n))  (a>b)

由此可得,本题要求x^gcd(a,b)-1;

再考虑每一个gcd值(d)可能对应多个数对,而只要求出对应多少个数对(sd),就能直接由乘法得出结论。

那么怎么求N以内最大公约数是d的对数,那就是欧拉函数的事了。对每一个d,其值就是:

2*(phi[1]+...+phi[n/d])-1。这个不做过多解释。(减一是因为phi[1]在计算的时候会算上两遍,也就是扩大d倍之后a==b算了一遍,而b==a时又算了一遍);

但是就是维护了前缀和,一个一个点算仍然超时,因为T太大。

所以考虑把相同sd值的数全都合并,跳着加一段,剩下的等比数列逆元搞。(比如对n=10来说,i=6一直到i=10都相等,因为n/i相等,这样每次延伸到最右端,也就是logn,而预处理的nlogn,是可以接受的)。

#include <cstdio>
#include <cstring>
#include <vector>
#include <cmath>
#include <stack>
#include <cstdlib>
#include <queue>
#include <map>
#include <iostream>
#include <algorithm>
#define mod 1000000007
using namespace std;
typedef long long LL;
int N = 1000100;


LL prime[1000100];
LL phi[1000100];
LL inv[1000100];
LL sum_phi[1000100];
bool is_prime[1000100];
LL quick_mod(LL a,LL b)
{
    LL ans=1;
    a%=mod;
    while(b)
    {
        if(b&1)
        {
            ans=ans*a%mod;
            b--;
        }
        b>>=1;
        a=a*a%mod;
    }
    return ans;
}
void init()
{
    phi[1]=1;
    for(int i=2; i<=N; ++i)
    {
        if(!phi[i])
        {
            prime[++prime[0]]=i;
            phi[i]=i-1;
        }
        for(int j=1; j<=prime[0]&&i*prime[j]<=N; ++j)
            if(i%prime[j])phi[i*prime[j]]=phi[i]*(prime[j]-1);
            else phi[i*prime[j]]=phi[i]*prime[j];
    }

    for (int i=1; i<N; i++)
    {
        phi[i]=(phi[i-1]+phi[i])%mod;
    }
    inv[1] = inv[0] = 1;
    for(int i = 2; i < N; i++)
        inv[i] = inv[mod%i]*(mod-mod/i)%mod;
//    for (int i=0;i<N;i++)
//    {
//        printf ("%lld ",phi[i]);
//        system("pause");
//    }
}
LL he(LL q,LL n)
{
    if (q==1) return n;
    return (quick_mod(q,n)-1)*inv[q-1]%mod;
}
LL n,x;
int main()
{
    init();
    int T;
    scanf ("%d",&T);
    while (T--)
    {
        scanf ("%I64d%I64d",&x,&n);
        int j;
        long long ans=0;
        for (int i=1; i<=n; i=j+1)
        {
            j=n/(n/i);
            LL sd=2*phi[n/i]-1;
            ans=(ans+sd*(quick_mod(x,i)*he(x,j-i+1)%mod-(j-i+1))%mod)%mod;
        }
        printf ("%I64d\n",ans);
    }
    return 0;
}

 

posted on 2016-08-07 15:11  very_czy  阅读(168)  评论(0编辑  收藏  举报

导航