標題
有函數
fn(k)=l1=1∑nl2=1∑n⋯lk=1∑ngcd(l1,l2,⋯,lk)2
求
i=2∑kfn(i)mod1e9+7
其中1≤n≤109,2≤k≤10105
思路
第一步我們肯定先對fn(k)進行化簡,先把gcd提出來
fn(k)=d=1∑nd2l1=1∑nl2=1∑n⋯lk=1∑n[gcd(l1,l2,⋯,lk)==d]
後面部分都除個d
fn(k)=d=1∑nd2l1=1∑dnl2=1∑dn⋯lk=1∑dn[gcd(l1,l2,⋯,lk)==1]
將∑d∣gcd(l1,l2,⋯,lk)μ(d)=[gcd(l1,l2,⋯,lk)==1]帶入
fn(k)=d=1∑nd2l1=1∑dnl2=1∑dn⋯lk=1∑dni∣gcd(l1,l2,⋯,lk)∑μ(i)
將i提出有,及枚舉1到dn內的倍數,所以有
fn(k)=d=1∑nd2i=1∑dnμ(i)l1=1∑idnl2=1∑idn⋯lk=1∑idn1
後面的部分及idn的k次冪即
fn(k)=d=1∑nd2i=1∑dnμ(i)⌊idn⌋k上式等價於
fn(k)=d=1∑nd2id=1∑nμ(i)⌊idn⌋k
我們令T=id帶入有
fn(k)=d=1∑nT=1∑n[T%d==0]d2μ(dT)⌊Tn⌋k
這裏可以看作枚舉的是1到n中每一個d的倍數,那麼我們也等價於枚舉1到n中每個數T的因子
fn(k)=T=1∑n⌊Tn⌋kd∣T∑d2μ(dT)
然後我們考慮求解設有函數S(n),f(n)
S(n)=i=1∑nf(i)=i=1∑nd∣T∑d2μ(dT)
對於函數f(n)爲Id2和μ的迪利克雷卷積即
f(n)=(Id2∗μ)(n)
我們又知道μ∗I=e
我們令g(n)=I(n)=1讓g和f進行卷積然後對其求和,即用杜教篩
i=1∑ng∗f=i=1∑nId2(i)=i=1∑ni2=6n(n+1)(2n+1)
所以這兩個函數的卷積的前綴和是很好求的
i=1∑nd∣i∑g(d)f(di)
對於這個式子是枚舉1到n中每個數的因子的,他和枚舉1到n中每個數的倍數是等價的那就有
i=1∑nd∣i∑g(d)f(di)=d=1∑ni=1∑⌊dn⌋g(d)f(i)=d=1∑ng(d)i=1∑⌊dn⌋f(i)=d=1∑ng(d)S(⌊dn⌋)
d=1∑ng(d)S(⌊dn⌋)=g(1)S(n)+d=2∑ng(d)S(⌊dn⌋)=i=1∑ni2
g(1)S(n)=i=1∑ni2−d=2∑ng(d)S(⌊dn⌋)
由於g(n)=1,所以
S(n)=6n(n+1)(2n+1)−d=2∑nS(⌊dn⌋)
對於f函數我們要先預處理一部分前綴和這樣可以降低杜教篩的複雜度
f函數是一個積性函數,顯然可以用積性函數線性篩,即記錄一個low[i],low[i]的含義是記錄將i唯一分解後最小的質數的次冪,即low[i]=pk,那麼在線性篩中當i%prime[j]==0時,low[i]i和low[i]∗prime[j]肯定是互質的,那麼就可以通過積性函數的性質互質的兩個數f(i)∗f(j)=f(ij),所以f[i∗prime[j]]=f[i/low[i]]∗f[low[i]∗prime[j]]。但是還有一種情況就是當i==low[i]時,i中不含有其他因子那麼有我們要處理一下f(pk)這種,通過手寫幾項就可以發現有遞推式f[i∗prime[j]]=f[i]∗prime[j],即f(pk+1)=f(pk)∗p,這樣就可以篩了
再回到原函數fn(k)中,有last=Tnn,那麼fn(k)就可以分塊做有
fn(k)=T=1∑n(S(last)−S(T−1))⌊Tn⌋k
題目要求的是
i=2∑kfn(i)=T=1∑n(S(last)−S(T−1))i=2∑k⌊Tn⌋i
令q=⌊Tn⌋,那麼後面就是一個等比數列求和有
i=2∑kfn(i)=T=1∑n(S(last)−S(T−1))q−1qk+1−q2
注意還有公比爲1的情況,所以實際上的答案爲
i=2∑kfn(i)=T=1∑n(S(last)−S(T−1))q−1qk+1−q2[q!=1]+(S(last)−S(T−1))(k−1)[q==1]
還有一點值得注意的是他的k很大,在求解qk+1次冪的時候要用上歐拉降冪這個時候對輸入的kmod1e9+6,而當公比爲1的時候用的是輸入的kmod1e9+7,記錄兩個k的值
#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;
}