The Preliminary Contest for ICPC Asia Nanjing 2019 南京網絡賽 E. K Sum(杜教篩+歐拉降冪)

標題

有函數
fn(k)=l1=1nl2=1nlk=1ngcd(l1,l2, ,lk)2f_{n}(k)=\sum_{l_1=1}^{n}\sum_{l_2=1}^{n}\cdots\sum_{l_k=1}^{n}gcd(l_1,l_2,\cdots,l_k)^2

i=2kfn(i)mod  1e9+7\sum_{i=2}^kf_n(i)\mod 1e9+7
其中1n1091\le n\le 10^9,2k101052\le k \le 10^{10^5}

思路

第一步我們肯定先對fn(k)f_n(k)進行化簡,先把gcdgcd提出來
fn(k)=d=1nd2l1=1nl2=1nlk=1n[gcd(l1,l2, ,lk)==d]f_n(k)=\sum_{d=1}^nd^2\sum_{l_1=1}^{n}\sum_{l_2=1}^{n}\cdots\sum_{l_k=1}^{n}[gcd(l_1,l_2,\cdots,l_k)==d]
後面部分都除個dd
fn(k)=d=1nd2l1=1ndl2=1ndlk=1nd[gcd(l1,l2, ,lk)==1]f_n(k)=\sum_{d=1}^nd^2\sum_{l_1=1}^{\frac{n}{d}}\sum_{l_2=1}^{\frac{n}{d}}\cdots\sum_{l_k=1}^{\frac{n}{d}}[gcd(l_1,l_2,\cdots,l_k)==1]
dgcd(l1,l2, ,lk)μ(d)=[gcd(l1,l2, ,lk)==1]\sum_{d|gcd(l_1,l_2,\cdots,l_k)}\mu(d)=[gcd(l_1,l_2,\cdots,l_k)==1]帶入
fn(k)=d=1nd2l1=1ndl2=1ndlk=1ndigcd(l1,l2, ,lk)μ(i)f_n(k)=\sum_{d=1}^nd^2\sum_{l_1=1}^{\frac{n}{d}}\sum_{l_2=1}^{\frac{n}{d}}\cdots\sum_{l_k=1}^{\frac{n}{d}}\sum_{i|gcd(l_1,l_2,\cdots,l_k)}\mu(i)
ii提出有,及枚舉1到nd\frac{n}{d}內的倍數,所以有

fn(k)=d=1nd2i=1ndμ(i)l1=1nidl2=1nidlk=1nid1f_n(k)=\sum_{d=1}^nd^2\sum_{i=1}^{\frac{n}{d}}\mu(i)\sum_{l_1=1}^{\frac{n}{id}}\sum_{l_2=1}^{\frac{n}{id}}\cdots\sum_{l_k=1}^{\frac{n}{id}}1
後面的部分及nid\frac{n}{id}kk次冪即
fn(k)=d=1nd2i=1ndμ(i)nidkf_n(k)=\sum_{d=1}^nd^2\sum_{i=1}^{\frac{n}{d}}\mu(i)\left \lfloor \frac{n}{id} \right \rfloor^k上式等價於
fn(k)=d=1nd2id=1nμ(i)nidkf_n(k)=\sum_{d=1}^nd^2\sum_{id=1}^{n}\mu(i)\left \lfloor \frac{n}{id} \right \rfloor^k
我們令T=idT=id帶入有
fn(k)=d=1nT=1n[T%d==0]d2μ(Td)nTkf_n(k)=\sum_{d=1}^n\sum_{T=1}^{n}[T\%d==0]d^2\mu(\frac{T}{d})\left \lfloor \frac{n}{T} \right \rfloor^k
這裏可以看作枚舉的是11nn中每一個dd的倍數,那麼我們也等價於枚舉11nn中每個數TT的因子
fn(k)=T=1nnTkdTd2μ(Td)f_n(k)=\sum_{T=1}^n\left \lfloor \frac{n}{T} \right \rfloor^k\sum_{d|T}d^2\mu(\frac{T}{d})
然後我們考慮求解設有函數S(n)S(n),f(n)f(n)
S(n)=i=1nf(i)=i=1ndTd2μ(Td)S(n)=\sum_{i=1}^nf(i)=\sum_{i=1}^n\sum_{d|T}d^2\mu(\frac{T}{d})
對於函數f(n)f(n)Id2Id^2μ\mu的迪利克雷卷積即
f(n)=(Id2μ)(n)f(n)=(Id^2*\mu)(n)
我們又知道μI=e\mu*I=e
我們令g(n)=I(n)=1g(n)=I(n)=1ggff進行卷積然後對其求和,即用杜教篩
i=1ngf=i=1nId2(i)=i=1ni2=n(n+1)(2n+1)6\sum_{i=1}^ng*f=\sum_{i=1}^nId^2(i)=\sum_{i=1}^ni^2=\frac{n(n+1)(2n+1)}{6}
所以這兩個函數的卷積的前綴和是很好求的

i=1ndig(d)f(id)\sum_{i=1}^n\sum_{d|i}g(d)f(\frac{i}{d})
對於這個式子是枚舉1到n中每個數的因子的,他和枚舉1到n中每個數的倍數是等價的那就有
i=1ndig(d)f(id)=d=1ni=1ndg(d)f(i)=d=1ng(d)i=1ndf(i)=d=1ng(d)S(nd)\sum_{i=1}^n\sum_{d|i}g(d)f(\frac{i}{d})=\sum_{d=1}^n\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}g(d)f(i)=\sum_{d=1}^ng(d)\sum_{i=1}^{\left \lfloor \frac{n}{d} \right \rfloor}f(i)=\sum_{d=1}^ng(d)S(\left \lfloor \frac{n}{d} \right \rfloor)
d=1ng(d)S(nd)=g(1)S(n)+d=2ng(d)S(nd)=i=1ni2\sum_{d=1}^ng(d)S(\left \lfloor \frac{n}{d} \right \rfloor)=g(1)S(n)+\sum_{d=2}^ng(d)S(\left \lfloor \frac{n}{d} \right \rfloor)=\sum_{i=1}^ni^2
g(1)S(n)=i=1ni2d=2ng(d)S(nd)g(1)S(n)=\sum_{i=1}^ni^2-\sum_{d=2}^ng(d)S(\left \lfloor \frac{n}{d} \right \rfloor)
由於g(n)=1g(n)=1,所以
S(n)=n(n+1)(2n+1)6d=2nS(nd)S(n)=\frac{n(n+1)(2n+1)}{6}-\sum_{d=2}^nS(\left \lfloor \frac{n}{d} \right \rfloor)
對於ff函數我們要先預處理一部分前綴和這樣可以降低杜教篩的複雜度

ff函數是一個積性函數,顯然可以用積性函數線性篩,即記錄一個low[i]low[i]low[i]low[i]的含義是記錄將i唯一分解後最小的質數的次冪,即low[i]=pklow[i]=p^k,那麼在線性篩中當i%prime[j]==0i\%prime[j]==0時,ilow[i]\frac{i}{low[i]}low[i]prime[j]low[i]*prime[j]肯定是互質的,那麼就可以通過積性函數的性質互質的兩個數f(i)f(j)=f(ij)f(i)*f(j)=f(ij),所以f[iprime[j]]=f[i/low[i]]f[low[i]prime[j]]f[i*prime[j]]=f[i/low[i]]*f[low[i]*prime[j]]。但是還有一種情況就是當i==low[i]i==low[i]時,ii中不含有其他因子那麼有我們要處理一下f(pk)f(p^k)這種,通過手寫幾項就可以發現有遞推式f[iprime[j]]=f[i]prime[j]f[i*prime[j]]=f[i]*prime[j],即f(pk+1)=f(pk)pf(p^{k+1})=f(p^k)*p,這樣就可以篩了

再回到原函數fn(k)f_n(k)中,有last=nnTlast=\frac{n}{\frac{n}{T}},那麼fn(k)f_n(k)就可以分塊做有

fn(k)=T=1n(S(last)S(T1))nTkf_n(k)=\sum_{T=1}^n(S(last)-S(T-1))\left \lfloor \frac{n}{T} \right \rfloor^k
題目要求的是
i=2kfn(i)=T=1n(S(last)S(T1))i=2knTi\sum_{i=2}^kf_n(i)=\sum_{T=1}^n(S(last)-S(T-1))\sum_{i=2}^k\left \lfloor \frac{n}{T} \right \rfloor^i
q=nTq=\left \lfloor \frac{n}{T} \right \rfloor,那麼後面就是一個等比數列求和有
i=2kfn(i)=T=1n(S(last)S(T1))qk+1q2q1\sum_{i=2}^kf_n(i)=\sum_{T=1}^n(S(last)-S(T-1))\frac{q^{k+1}-q^2}{q-1}
注意還有公比爲11的情況,所以實際上的答案爲
i=2kfn(i)=T=1n(S(last)S(T1))qk+1q2q1[q!=1]+(S(last)S(T1))(k1)[q==1]\sum_{i=2}^kf_n(i)=\sum_{T=1}^n(S(last)-S(T-1))\frac{q^{k+1}-q^2}{q-1}[q!=1]+(S(last)-S(T-1))(k-1)[q==1]
還有一點值得注意的是他的kk很大,在求解qk+1q^{k+1}次冪的時候要用上歐拉降冪這個時候對輸入的kmod  1e9+6k\mod 1e9+6,而當公比爲11的時候用的是輸入的kmod  1e9+7k\mod 1e9+7,記錄兩個kk的值

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
const int mod=1e9+7;
const int p=mod-1;
const int inv6=166666668;
bool vis[N];
int prime[N];
long long f[N];
int low[N];
int cnt;
void init()
{
    f[1]=low[1]=1;
    cnt=0;
    for(int i=2; i<N; i++)
    {
        if(!vis[i])
        {
            prime[cnt++]=i;
            f[i]=(1ll*i*i-1+mod)%mod;
            low[i]=i;
        }
        for(int j=0; j<cnt&&i*prime[j]<N; j++)
        {
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                low[i*prime[j]]=low[i]*prime[j];
                if(i==low[i])
                {
                    f[i*prime[j]]=f[i]*prime[j]%mod*prime[j]%mod;
                }
                else
                {
                    f[i*prime[j]]=f[i/low[i]]*f[low[i]*prime[j]]%mod;
                }
                break;
            }
            else
            {
                low[i*prime[j]]=prime[j];
                f[i*prime[j]]=f[i]*f[prime[j]]%mod;
            }
        }
    }
    for(int i=1; i<N; i++)
        f[i]=(f[i-1]+f[i])%mod;
}
map<long long,long long>F;
long long S(long long n)
{
    if(n<N) return f[n];
    if(F.find(n)!=F.end()) return F[n];
    long long sum=n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
    for(long long i=2,last; i<=n; i=last+1)
    {
        last=n/(n/i);
        sum=(sum-(last-i+1)%mod*S(n/i)%mod+mod)%mod;
    }
    F[n]=sum;
    return sum;
}
long long quickmod(long long a,long long b)
{
    long long ans=1;
    while(b)
    {
        if(b%2==1)
            ans=ans*a%mod;
        a=a*a%mod;
        b=b/2;
    }
    return ans;
}
char str[100005];
int main()
{
    init();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        int n;
        scanf("%d%s",&n,str);
        long long k1=0;
        long long k2=0;
        int len=strlen(str);
        for(int i=0;i<len;i++)
        {
            k1=k1*10+str[i]-'0';
            k1%=p;
            k2=k2*10+str[i]-'0';
            k2%=mod;
        }
        long long ans=0;
        for(int i=1,last;i<=n; i=last+1)
        {
            last=n/(n/i);
            if((n/i)!=1)
            {
                ans=(ans+(S(last)-S(i-1)+mod)%mod*(quickmod(n/i,k1+1)%mod-1ll*(n/i)*(n/i)%mod+mod)%mod*quickmod(n/i-1,mod-2)%mod)%mod;
            }
            else
            {
                ans=(ans+(S(last)-S(i-1)+mod)%mod*((k2-1+mod)%mod)%mod)%mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}


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