[BZOJ4407]于神之怒加强版-题解

【题目地址】


题意简述

给定 T , K T,K T,K,表示有 T T T组询问,每组给定 n , m n,m n,m,求下面式子的值:

∑ i = 1 n ∑ j = 1 m g c d ( i , j ) K \sum_{i=1}^n\sum_{j=1}^mgcd(i,j)^K i=1nj=1mgcd(i,j)K

输出在 m o d    1 0 9 + 7 \mod 10^9+7 mod109+7意义下的值。
n , m , K ≤ 5 × 1 0 6 , T ≤ 2000 n,m,K\leq 5\times 10^6,T\leq 2000 n,m,K5×106,T2000


其实莫比乌斯反演的题目大多都是套路啦QWQ

根据套路,我们枚举 g c d gcd gcd,即可将原式转换为(这里默认 n ≤ m n\leq m nm,如果不满足则交换):

= ∑ d = 1 n d K ∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = d ] = ∑ d = 1 n d K ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ [ g c d ( i , j ) = 1 ] = ∑ d = 1 n d K ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ ∑ w ∣ i , w ∣ j μ ( w ) = ∑ d = 1 n d K ∑ w = 1 ⌊ n d ⌋ μ ( w ) ⌊ n d w ⌋ ⌊ m d w ⌋ =\sum_{d=1}^nd^K\sum_{i=1}^n\sum_{j=1}^m[gcd(i,j)=d]\\ =\sum_{d=1}^nd^K\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[gcd(i,j)=1]\\ =\sum_{d=1}^nd^K\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\sum_{w|i,w|j}\mu(w)\\ =\sum_{d=1}^nd^K\sum_{w=1}^{\lfloor\frac{n}{d}\rfloor}\mu(w)\left\lfloor\frac{n}{dw}\right\rfloor\left\lfloor\frac{m}{dw}\right\rfloor =d=1ndKi=1nj=1m[gcd(i,j)=d]=d=1ndKi=1dnj=1dm[gcd(i,j)=1]=d=1ndKi=1dnj=1dmwi,wjμ(w)=d=1ndKw=1dnμ(w)dwndwm

这些都是莫比乌斯反演的套路啦,接下来,为了每次能够在 O ( n ) O(\sqrt{n}) O(n )的时间内快速回答,我们就枚举 d w dw dw,令 T = d w T=dw T=dw则得到:

∑ T = 1 n ⌊ n T ⌋ ⌊ m T ⌋ ∑ d ∣ T d K μ ( T d ) \sum_{T=1}^n\left\lfloor\frac{n}{T}\right\rfloor\left\lfloor\frac{m}{T}\right\rfloor\sum_{d|T}d^K\mu(\frac{T}{d}) T=1nTnTmdTdKμ(dT)

然后我们线性筛出后面的:
f ( n ) = ∑ d ∣ n d K μ ( T d ) f(n)=\sum_{d|n}d^K\mu(\frac{T}{d}) f(n)=dndKμ(dT)
即可(这个显然是个积性函数, f = i d k ⨂ μ f=id^k\bigotimes \mu f=idkμ两个积性函数的狄利克雷卷积也是积性函数)。

也可以枚举倍数用 O ( n ( l o g n × 快 速 幂 ) ) O(n(logn\times快速幂)) O(n(logn×))的复杂度算,但是在这个题上面就太慢了,5e6可能有点卡。

我们根据欧拉筛三步走来推:

  1. 考虑 f ( p ) f(p) f(p) p p p为质数的值的计算:

∑ d ∣ p d k μ ( p d ) \sum_{d|p}d^k\mu(\frac{p}{d}) dpdkμ(dp)
显然, d = 1 , p d=1,p d=1,p这两个,所以直接算出为 p k − 1 p^k-1 pk1

  1. 考虑 f ( p c ) f(p^c) f(pc) p p p为质数的值的计算:

∑ d ∣ p c d k μ ( p c d ) = ∑ i = 0 c ( p i ) k μ ( p c p i ) = ∑ i = 0 c ( p i ) k μ ( p c − i ) \sum_{d|p^c}d^k\mu(\frac{p^c}{d})\\ =\sum_{i=0}^c(p^i)^k\mu(\frac{p^c}{p^i})\\ =\sum_{i=0}^c(p^i)^k\mu(p^{c-i}) dpcdkμ(dpc)=i=0c(pi)kμ(pipc)=i=0c(pi)kμ(pci)

由于当指数大于1的时候 μ ( p i ) = 0 \mu(p^i)=0 μ(pi)=0,所以只有 i = c , c − 1 i=c,c-1 i=c,c1两个有值,直接代入计算即可,答案为 p k c − p k c − k p^{kc}-p^{kc-k} pkcpkck

  1. 考虑 f ( x ) f(x) f(x) x = p c y x=p^cy x=pcy,其中 p ⊥ y p\bot y py

那么根据积性函数,直接转化为 f ( x ) = f ( p c ) f ( y ) f(x)=f(p^c)f(y) f(x)=f(pc)f(y)即可,其中的 f ( y ) = f ( x p c ) f(y)=f(\frac{x}{p^c}) f(y)=f(pcx)

上面有些小写 k k k就是大写的 K K K,懒得改了QWQ

下面就是代码了:

#include
#include
#include
#define ll long long
using namespace std;
const ll Mod=1e9+7;
const int M=5e6+10,MAX=5e6;
int n,m,K,T;
ll fpow(ll a,ll b){
     
	ll ans=1;
	for(;b;b>>=1,a=(a*a)%Mod)if(b&1)ans=(ans*a)%Mod;
	return ans;
}
ll F[M],prime[M],P[M],Invp[M],cnt;
ll c[M],f[M],p[M];bool vis[M];
//ll C[M],mu[M];
void init(){
     
	F[1]=1;
//	mu[1]=1;
	for(int i=2;i<=MAX;i++){
     
		if(!vis[i]){
     
			prime[++cnt]=i;P[i]=fpow(i,K);Invp[i]=fpow(P[i],Mod-2);//逆元处理p^{-k}
			F[i]=P[i]-1;c[i]=1;f[i]=i;p[i]=i;
			if(F[i]<0)F[i]+=Mod;
//			mu[i]=Mod-1;
		}
		for(int j=1,v;j<=cnt&&i*prime[j]<=MAX;j++){
     
			v=i*prime[j];
			vis[v]=1;
			if(!(i%prime[j])){
     
				c[v]=c[i]+1;f[v]=f[i];p[v]=p[i]*f[i];
				ll vv=fpow(P[f[v]],c[v]);
				F[v]=F[v/p[v]]*(((vv-vv*Invp[f[v]]%Mod)%Mod+Mod)%Mod)%Mod;
				break;
			}
			F[v]=F[i]*F[prime[j]]%Mod;
			c[v]=1;f[v]=prime[j];p[v]=prime[j];
//			mu[v]=(Mod-mu[i]);
		}
	}//nlogn的线性筛预处理 
//	for(int i=1;i<=MAX;i++){
     
//		ll v=fpow(i,K);
//		for(int j=i;j<=MAX;j+=i){
     
//			C[j]=(C[j]+v*mu[j/i]%Mod)%Mod;
//		}
//	}//nlog^2n的预处理 
	for(int i=2;i<=MAX;i++)F[i]=(F[i]+F[i-1])%Mod;
}
ll solve(){
     
	ll ans=0;
	if(n>m)swap(n,m);
	for(int i=1,j;i<=n;i=j+1){
     
		j=min(n/(n/i),m/(m/i));
		ans=(ans+((F[j]-F[i-1])%Mod+Mod)%Mod*(n/i)%Mod*(m/i)%Mod)%Mod;
	}
	return ans;
}
int main(){
     
	scanf("%d%d",&T,&K);
	init();
	while(T--){
     
		scanf("%d%d",&n,&m);
		printf("%lld\n",solve());
	}
	return 0;
}

拓展

其实如果这个题目只有一次询问,且 n , m ≤ 1 0 8 , K ≤ 50 n,m\leq 10^8,K\leq 50 n,m108,K50的话,无法线性筛的时候我们可以用杜教筛。

原式相当于 i d k ⨂ μ id^k\bigotimes \mu idkμ,我们令 f = i d k ⨂ μ , g = 1 f=id^k\bigotimes \mu,g=\mathbf{1} f=idkμ,g=1,那么 f ⨂ g = i d k ⨂ μ ⨂ 1 f\bigotimes g=id^k\bigotimes \mu\bigotimes \mathbf1 fg=idkμ1

先把后面两个卷起来可以得到 μ ⨂ 1 = ϵ \mu\bigotimes \mathbf1=\epsilon μ1=ϵ,那么 f ⨂ g = i d k f\bigotimes g=id^k fg=idk

套入杜教筛的公式中可以得到:

F ( n ) = ∑ i = 1 n i k − ∑ i = 2 n F ( ⌊ n i ⌋ ) F(n)=\sum_{i=1}^ni^k-\sum_{i=2}^nF(\left\lfloor\frac{n}{i}\right\rfloor) F(n)=i=1niki=2nF(in)

其中 i k i^k ik的前缀和可以用拉格朗日差值法在 O ( k l o g k ) O(klogk) O(klogk)的时间内求出,所以总的复杂度为 O ( n 2 3 k l o g k ) O(n^{\frac{2}{3}}klogk) O(n32klogk),在3s左右能跑出 n ≤ 1 0 8 , K ≤ 50 n\leq10^8,K\leq 50 n108,K50


End

吐槽:莫比乌斯反演和杜教筛的题目都是好多套路和很多神奇的式子啊QWQ,要多写写题,总结总结

其实很多时候杜教筛不知道用什么 g g g函数去卷要求的 f f f函数,可以根据经验积累,或者使用贝尔级数之类的去推。

如果杜教筛中还有不好求的前缀和,可以再套一层杜教筛,复杂度仍然为 O ( n 2 3 ) O(n^{\frac{2}{3}}) O(n32),只是空间时间常数大了。

你可能感兴趣的:(OI数论,莫比乌斯反演,数论)