2019 ICPC南京網絡賽 E. K sum (莫比烏斯反演+杜教篩)**

題目鏈接:https://nanti.jisuanke.com/t/41302

Define function

fn(k)=∑l1=1n∑l2=1n…∑lk=1n(gcd⁡(l1,l2,…,lk))2\displaystyle f_n(k)=\sum_{l_1=1}^n \sum_{l_2=1}^n … \sum_{l_k=1}^n (\gcd(l_1,l_2,…,l_k))^2 fn​(k)=l1​=1∑n​l2​=1∑n​…lk​=1∑n​(gcd(l1​,l2​,…,lk​))2
.

Given n(1≤n≤109),k(2≤k≤10105)n(1 \le n \le 10^9),k(2 \le k \le {10}{105})n(1≤n≤109),k(2≤k≤10105), please calculate

∑i=2kfn(i)\displaystylei=2kfn(i)i=2kfn(i)\sum_{i=2}^k {f_n(i)} i=2∑k​fn​(i)

modulo 109+710^9 + 7109+7.
Input

There are multiple test cases, the first line contains an integer T(1≤T≤10)T(1 \le T \le 10)T(1≤T≤10), denoting the number of test cases.

For the next TTT lines, each line contains two integers n(1≤n≤109)n(1 \le n \le 10^9)n(1≤n≤109) and k(2≤k≤10105)k(2 \le k \le 10{105})k(2≤k≤10105).
Output

For each test case, print one line contains an integer, which is the value of ∑i=2kfn(i)\sum_{i=2}^k {f_n(i)}∑i=2k​fn​(i).
樣例輸入

2
2 2
100 3

樣例輸出

7
4331084


分析:

f(k)=l1=1nl2=1nlk=1n(gcd(l1,l2,,lk))2i=2kf(i)已知:f(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}}} \\ 求\sum_{i=2}^k{f(i)}

推式子:

f(k)=l1=1nl2=1nlk=1n(gcd(l1,l2,,lk))2=l1=1nl2=1nlk=1nd=1nd2[gcd(l1,l2,,lk)=d]=d=1nd2l1=1ndl2=1ndlk=1nd[gcd(l1,l2,,lk)==1]=d=1nd2l1=1ndl2=1ndlk=1nd      (igcd(l1,l2,,lk)μ(i)1)                        =d=1nd2i=1ndμ(i)l1=1ndl2=1ndlk=1nd[il1][il2][ilk]=d=1nd2i=1ndμ(i)(nid)kk便t=id,it,d=t/i=t=1n(nt)kitμ(i)(ti)2f(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}}} \\ = \sum_{l_1=1}^n{\sum_{l_2=1}^n{\cdots \sum_{l_k=1}^n{\sum_{d=1}^n{d^2}}[gcd(l_1,l_2,\cdots,l_k)=d]}} \\ =\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]} \\ = \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)*1})} \;\;\;\;\;\;\;\;\;\;\;\;{莫比烏斯反演} \\ = \sum_{d=1}^n{d^2}\sum_{i=1}^{\frac{n}{d}}{\mu(i)\sum_{l_1=1}^{\frac{n}{d}}\sum_{l_2=1}^{\frac{n}{d}}\cdots\sum_{l_k=1}^{\frac{n}{d}}[i|l_1][i|l_2]\cdots[i|l_k]} \\=\sum_{d=1}^nd^2\sum_{i=1}^{\frac{n}{d}}\mu(i)(\frac{n}{i*d})^k \\爲了將k次方化成便於計算的,令t=i*d,則有i|t,d=t/i \\=\sum_{t=1}^n(\frac{n}{t})^k \sum_{i|t}\mu(i)(\frac{t}{i})^2


i=2kf(i)\sum_{i=2}^kf(i)將f(i)代入得:(f(i)中變量名換下)
=i=2kt=1n(nt)idtμ(d)(td)2=t=1n(i=2k(nt)i)dtμ(d)(td)2(1)=\sum_{i=2}^k{\sum_{t=1}^n(\frac{n}{t})^i \sum_{d|t}\mu(d)(\frac{t}{d})^2} \\ =\sum_{t=1}^n(\sum_{i=2}^k(\frac{n}{t})^i) \sum_{d|t}\mu(d)(\frac{t}{d})^2\tag{1}
對於i=2k(nt)i\sum_{i=2}^k(\frac{n}{t})^i這部分可以利用等比數列求解,並對公比爲1的情況特判,只需將k%mod,其餘情況k%φ(mod),
對於後面那部分:s(t)=dtμ(d)(td)2令s(t)=\sum_{d|t}\mu(d)(\frac{t}{d})^2,這個函數s(t)是積性函數,s(1)=1,s(p)=pp1,s(pk)=p2k2(p21)s(1)=1,s(p)=p*p-1,s(p^k)=p^{2k-2}(p^2-1),對於s函數在線性篩中,稍微推下,就可推出
在(1)式中,n/t可以利用分塊, 故要對s函數求前綴和,令前i個和爲sum(i),前綴和杜教篩推導:

id(i)=i,I(i)=1g(i)=i2s=μgμI=[i==1]h=sI=μIg=g,h(i)=i2sum(i)i=1nh(i)=i=1ndiI(d)s(i/d)i=1nh(i)=d=1nI(d)k=1nds(k)=d=1nI(d)sum(nd)d=1i=1nh(i)=I(1)sum(n)+d=2nI(d)sum(nd)h,Isum(n)=i=1ni2d=2nsum(nd)前置知識:id(i)=i,I(i)=1;卷積;\\令g(i)=i^2\\則有s=\mu*g \\ 又\mu*I=[i==1]\\ 令h=s*I=\mu*I*g=g,即h(i)=i^2\\ \\ 推sum(i)\\ \sum_{i=1}^nh(i)=\sum_{i=1}^n\sum_{d|i}I(d)*s(i/d) \\ \sum_{i=1}^nh(i)=\sum_{d=1}^nI(d)\sum_{k=1}^{\frac{n}{d}}s(k)=\sum_{d=1}^nI(d)sum(\frac{n}{d}) \\提出右邊的d=1 \\ \sum_{i=1}^nh(i)=I(1)sum(n)+\sum_{d=2}^nI(d)sum(\frac{n}{d}) \\ h,I函數代入得 sum(n)=\sum_{i=1}^ni^2-\sum_{d=2}^nsum(\frac{n}{d})

然後利用杜教篩的這個式子分塊求sum(i)

代碼:

#include <bits/stdc++.h>

using namespace std;
#define ll long long 
const ll mod = 1e9+7;
const ll N= 3e6+5;


int prime[N+1];
ll s[N+1];
ll sum[N+1];
unordered_map<int,ll> mpsum;
char str[N];

void init_prime()
{
	
	s[1]=1;
	sum[1]=1;
	for(int i=2;i<=N;i++)
	{
		if(!prime[i])
		{
			prime[++prime[0]]=i;
			s[i]=((1LL*i*i-1)%mod+mod)%mod;
		}
		for(int j=1;j<=prime[0] && i*prime[j]<=N;j++)
		{
			prime[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				s[i*prime[j]]=1LL*prime[j]*prime[j]%mod*s[i]%mod;
				break;
			}
			s[i*prime[j]]=1LL*s[prime[j]]*s[i]%mod;
		}
		sum[i]= (sum[i-1]+s[i])%mod;
		
	}
}

ll get_sum(ll n)
{
	if(n<=N) return sum[n];
	if(mpsum.count(n)) return mpsum[n];
	
	ll ans=1LL*n*(n+1)%mod*((1ll*2*n+1)%mod)%mod*((mod+1)/6)%mod;
	for(int l=2,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans -= 1LL*(r-l+1)*get_sum(n/l);
		
	}
	ans=(ans%mod+mod)%mod;
	return mpsum[n]=ans;
}

ll mul(ll a, ll b)
{
	ll ans=1;
	ll bs=a;
	while(b)
	{
		if(b&1) 
			ans= ans*bs%mod;
		b>>=1;
		bs=bs*bs%mod;
	}
	return ans;
}

ll get_k(char* str,ll& k2)
{
	int len= strlen(str);
	ll p=0;
	k2=0;
	for(int i=0;i<len;i++)
	{
		p=1ll*10*p+str[i]-'0';
		k2=1ll*10*k2+str[i]-'0';
		if(p>=mod-1)
			p%=(mod-1);
		if(k2>=mod)
			k2%=mod;
	}
	
	return p;
		
}

ll fp(ll a,ll k,ll k2)
{
	if(a==1) return ((k2-1)%mod+mod)%mod;
	return mul(a-1,mod-2)*(((mul(a,k+1)-1LL*a*a)%mod+mod)%mod)%mod;
}
ll solve(ll n,ll k,ll k2)
{
	ll ans=0;
	ll w,tmp;
	ll x, y;
	for(int l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		ans += (get_sum(r)-get_sum(l-1))%mod*fp(n/l,k,k2)%mod;
		
	}
	ans%=mod;
	if(ans<0) ans+=mod;
	return ans;
}



int main()
{
	
	init_prime();
	ll t, n ;
	ll k;
	ll k2;
	scanf("%lld",&t);
	while(t--)
	{
		scanf("%lld %s",&n,str);
		k=get_k(str,k2);
		printf("%lld\n",solve(n,k,k2));
	}
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章