HDU 6706 huntian oy【杜教篩】

題目鏈接:http://acm.hdu.edu.cn/showproblem.php?pid=6706

題目大意:給定n,a,bn,a,b,保證a,ba,b互質,
計算f(n,a,b)=i=1nj=1igcd(iaja,ibjb)[gcd(i,j)=1]%(109+7)f(n,a,b)=\sum_{i=1}^n\sum_{j=1}^igcd(i^a-j^a,i^b-j^b)[gcd(i,j)=1]\%(10^9+7)

題解:
因爲a>ba>bgcd(a,b)=1gcd(a,b)=1,則有gcd(anbn,ambm)=agcd(n,m)bgcd(n,m)gcd(a^n-b^n,a^m-b^m)=a^{gcd(n,m)}-b^{gcd(n,m)}

證明 :
假設:n>=mn>=mr=n%mr=n \%m

anbn=(ambm)(anm+an2mbm++arbnmr)+arbnrbna^n-b^n=(a^m-b^m)*(a^{n-m}+a^{n-2m}b^m+\dots+a^rb^{n-m-r})+a^rb^{n-r}-b^n

gcd(anbn,ambm)=gcd(arbnrbn,ambm)=gcd(bnr(arbr),ambm)gcd(a^n-b^n,a^m-b^m)=gcd(a^rb^{n-r}-b^n,a^m-b^m)=gcd(b^{n-r}*(a^r-b^r),a^m-b^m)

bnr=bmnm=bkmb^{n-r}=b^{m\lfloor \frac{n}{m} \rfloor}=b^{km}

考慮gcd(bkm,ambm)gcd(b^{km},a^m-b^m)

bkm=(ambm)(b(k1)mamb(k2)ma(k1)m)+akmb^{km}=(a^m-b^m)*(-b^{(k-1)m}-a^mb^{(k-2)m}-\dots-a^{(k-1)m})+a^{km}

gcd(bkm,ambm)=gcd(akm,ambm)=dgcd(b^{km},a^m-b^m)=gcd(a^{km},a^m-b^m)=d

所以dbkm,dakm,dgcd(bkm,akm)=1d|b^{km},d|a^{km},d|gcd(b^{km},a^{km})=1

gcd(bnr,ambm)=1gcd(b^{n-r},a^m-b^m)=1

所以gcd(anbn,ambm)=gcd(an%mbn%m,ambm)=agcd(n,m)bgcd(n,m)gcd(a^n-b^n,a^m-b^m)=gcd(a^{n\%m}-b^{n\%m},a^m-b^m)=a^{gcd(n,m)}-b^{gcd(n,m)}
證畢。

那麼題目:

f(n,a,b)f(n,a,b)

=i=1nj=1igcd(iaja,ibjb)[gcd(i,j)=1]=\sum_{i=1}^n\sum_{j=1}^igcd(i^a-j^a,i^b-j^b)[gcd(i,j)=1]

=i=1nj=1i(ij)[gcd(i,j)=1]=\sum_{i=1}^n\sum_{j=1}^i(i-j)[gcd(i,j)=1]

=i=1nj=1ii[gcd(i,j)=1]i=1nj=1ij[gcd(i,j)=1]=\sum_{i=1}^n\sum_{j=1}^ii[gcd(i,j)=1]-\sum_{i=1}^n\sum_{j=1}^ij[gcd(i,j)=1]

=i=1niϕ(i)i=1n(iϕ(i)2+[i==1])=\sum_{i=1}^ni*\phi(i)-\sum_{i=1}^n(\frac{i*\phi(i)}{2}+[i==1])

=i=1niϕ(i)12=\frac{\sum_{i=1}^ni*\phi(i)-1}{2}

由杜教篩公式:S(n)g(1)=i=1n(fg)(i)i=2ng(i)S(ni)S(n)*g(1)=\sum_{i=1}^n(f*g)(i)-\sum_{i=2}^ng(i)S(\frac{n}{i})

這時候我們就可以通過構造f(n)=nϕ(n)f(n)=n*\phi(n)S(n)=i=1nf(i)S(n)=\sum_{i=1}^nf(i)g(n)=id(n)g(n)=id(n)作狄利克雷卷積杜教篩即可

(fg)(n)=dnnϕ(d)=ndnϕ(d)=n2(f*g)(n)=\sum_{d|n}n*\phi(d)=n\sum_{d|n}\phi(d)=n^2

最終杜教篩的公式:S(n)=i=1ni2i=2niS(ni)S(n)=\sum_{i=1}^ni^2-\sum_{i=2}^ni*S(\frac{n}{i}),前一部分直接算,後一部分可以用分塊求和做就okok了。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
int qpow(int x,int y)
{
    int ans=1;
    while(y>0){
        if(y&1){
            ans=(ll)ans*x%mod;
        }
        x=(ll)x*x%mod;
        y>>=1;
    }
    return ans;
}
const int maxn=1e6+10;
bool vis[maxn];
int tot=0,phi[maxn],prime[maxn];
int s[maxn];
void calphi()
{
    phi[1]=1;
    for(int i=2;i<maxn;i++){
        if(!vis[i]){
            prime[tot++]=i;
            phi[i]=i-1;
        }
        for(int j=0;j<tot;j++){
            if(i*prime[j]>maxn){ break;}
            vis[i*prime[j]]=1;
            if(i%prime[j]==0){
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            else{
                phi[i*prime[j]]=phi[i]*(prime[j]-1);
            }
        }
    }
    s[0]=0;
    for(int i=1;i<maxn;i++){
        s[i]=(ll)(s[i-1]+(ll)i*phi[i]%mod)%mod;//先預處理1e6以內的f(n)的值
    }
}
int inv_2,inv_6;
unordered_map<int,int>ard;//已經計算過的通過map映射,不需重複計算
int solve(int n)
{
    if(n<maxn){
        return s[n];
    }
    if(ard[n]){
        return ard[n];
    }
    int ans=(ll)n*(n+1)%mod*(2*n%mod+1)%mod*inv_6%mod;
    int l=2,r=n;
    while(l<=n){//分塊求和
        r=(n/(n/l));
        ans=(ans-(ll)(l+r)*(r-l+1)%mod*inv_2%mod*solve(n/l)%mod+mod)%mod;
        l=r+1;
    }
    ard[n]=ans;
    return ans;
}
int main()
{
    int t;
    scanf("%d",&t);
    calphi();
    int a,b;
    int n;
    inv_2=qpow(2,mod-2);
    inv_6=qpow(6,mod-2);
    while(t--){
        scanf("%d%d%d",&n,&a,&b);
        int ans=(ll)((solve(n)-1)%mod+mod)%mod*inv_2%mod;
        printf("%d\n",ans);
    }
    return 0;
}

杜教篩參考:https://www.cnblogs.com/peng-ym/p/9446555.html
參考:https://www.cnblogs.com/danzh/p/11405721.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章