[国家集训队]Crash的数字表格/JZPTAB和51Nod1238最小公倍数之和V3题解-数论

版权声明:转载注明出处,谢谢,有问题可以向博主联系 https://blog.csdn.net/VictoryCzt/article/details/85054670

[国家集训队]Crash的数字表格【地址BZOJ2145地址Luoguo

  • 题意简述

给你两个正整数 n , m n,m ,求下面式子在 m o d    20101009 \mod 20101009 意义下的值。

i = 1 n j = 1 m l c m ( i , j ) \sum_{i=1}^n\sum_{j=1}^mlcm(i,j)

n , m 1 0 7 n,m\leq 10^7


我们根据 l c m ( i j ) = i j g c d ( i , j ) lcm(ij)=\frac{ij}{gcd(i,j)} ,将原式化简成:

i = 1 n j = 1 m i j g c d ( i , j ) \sum_{i=1}^n\sum_{j=1}^m\frac{ij}{gcd(i,j)}

根据套路,我们枚举 g c d gcd ,原式则化成:
(这里默认 n m n\leq m ,如果不满足则交换)
= d = 1 n i = 1 n j = 1 m i j d [ g c d ( i , j ) = d ] = d = 1 n i = 1 n d j = 1 m d ( i d ) × ( j d ) d [ g c d ( i , j ) = 1 ] =\sum_{d=1}^n\sum_{i=1}^n\sum_{j=1}^m\frac{ij}{d}[gcd(i,j)=d]\\ = \sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}\frac{(id)\times(jd)}{d}[gcd(i,j)=1]

此时原式就可以变成:

d = 1 n d i = 1 n d j = 1 m d i j [ g c d ( i , j ) = 1 ] \sum_{d=1}^nd\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij[gcd(i,j)=1]

然后又用莫比乌斯反演,我们可以将原式变成:
= d = 1 n d i = 1 n d j = 1 m d i j w i , w j μ ( w ) = d = 1 n d w = 1 n d μ ( w ) i = 1 n d w i w j = 1 n d w j w =\sum_{d=1}^nd\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}ij\sum_{w|i,w|j}\mu(w)\\ =\sum_{d=1}^nd\sum_{w=1}^{\lfloor\frac{n}{d}\rfloor}\mu(w)\sum_{i=1}^{\lfloor\frac{n}{dw}\rfloor}iw\sum_{j=1}^{\lfloor\frac{n}{dw}\rfloor}jw

然后我们令 S ( n ) = i = 1 n i = n × ( n + 1 ) 2 S(n)=\sum_{i=1}^ni=\frac{n\times(n+1)}{2} ,原式就可以变成:

= d = 1 n d w = 1 n d μ ( w ) w 2 S ( n d w ) S ( m d w ) =\sum_{d=1}^nd\sum_{w=1}^{\lfloor\frac{n}{d}\rfloor}\mu(w)w^2S(\left\lfloor\frac{n}{dw}\right\rfloor)S(\left\lfloor\frac{m}{dw}\right\rfloor)

用线性筛筛出 μ ( w ) w 2 \mu(w)w^2 的前缀和,然后 S S 可以 O ( 1 ) O(1) 算,所以我们可以对于 H ( n , m ) = w = 1 n μ ( w ) w 2 S ( n w ) S ( m w ) H(n,m)=\sum_{w=1}^{n}\mu(w)w^2S(\left\lfloor\frac{n}{w}\right\rfloor)S(\left\lfloor\frac{m}{w}\right\rfloor) 用数论分块计算,而对于 d = 1 n H ( n d , m d ) \sum_{d=1}^nH(\left\lfloor\frac{n}{d}\right\rfloor,\left\lfloor\frac{m}{d}\right\rfloor) 又数论分块算即可,复杂度最坏为 O ( n + m ) O(n+m)


[国家集训队]JZPTAB【题目地址BZOJ2693

还是上面的问题, n , m 1 0 7 n,m\leq10^7 ,但是有 T 1 0 4 T\leq 10^4 组询问。

所以我们必须要做到 O ( n ) O(n) 预处理,每次 O ( n ) O(\sqrt{n}) 的回答。

我们还是看上一个化简后的式子:

= d = 1 n d w = 1 n d μ ( w ) w 2 S ( n d w ) S ( m d w ) =\sum_{d=1}^nd\sum_{w=1}^{\lfloor\frac{n}{d}\rfloor}\mu(w)w^2S(\left\lfloor\frac{n}{dw}\right\rfloor)S(\left\lfloor\frac{m}{dw}\right\rfloor)

还有一个套路就是,我们枚举 d w dw ,所以令 T = d w T=dw ,那么原式等于:

= T = 1 n S ( n T ) S ( m T ) d T d μ ( T d ) ( T d ) 2 = T = 1 n S ( n T ) S ( m T ) w T μ ( w ) w 2 T w = T = 1 n S ( n T ) S ( m T ) T w T μ ( w ) w =\sum_{T=1}^nS(\left\lfloor\frac{n}{T}\right\rfloor)S(\left\lfloor\frac{m}{T}\right\rfloor)\sum_{d|T}d\mu(\frac{T}{d})(\frac{T}{d})^2\\ =\sum_{T=1}^nS(\left\lfloor\frac{n}{T}\right\rfloor)S(\left\lfloor\frac{m}{T}\right\rfloor)\sum_{w|T}\mu(w)w^2\frac{T}{w}\\ =\sum_{T=1}^nS(\left\lfloor\frac{n}{T}\right\rfloor)S(\left\lfloor\frac{m}{T}\right\rfloor)T\sum_{w|T}\mu(w)w

对于前半部分我们每次数论分块求即可,而对于后面我们线性筛出它,然后求前缀和即可。

我们令 f ( x ) = x d x μ ( x ) x f(x)=x\sum_{d|x}\mu(x)x ,那么它肯定是个积性函数(因为相当于可以写成 i d ( ( μ i d ) 1 ) id\cdot ((\mu\cdot id)\bigotimes 1) )根据欧拉筛的方法我们只需维护三个东西 c n t , f i r , p o w cnt,fir,pow 即可,分别表示: c n t [ i ] cnt[i] i i 的最小质因子指数; f i r [ i ] fir[i] i i 的最小质因子; p o w [ i ] pow[i] 表示 f i r [ i ] c n t [ i ] fir[i]^{cnt[i]}

然后我们来看 f ( x ) f(x) 的计算方法:

  • x = p x=p 为质数, f ( x ) = x d x μ ( x ) x = x × ( μ ( 1 ) 1 + μ ( x ) x ) = x ( 1 x ) f(x)=x\sum_{d|x}\mu(x)x=x\times (\mu(1)1+\mu(x)x)=x(1-x)
  • x = p c x=p^c 时, p p 为质数,那么 f ( x ) = x k = 0 c μ ( p k ) p k f(x)=x\sum_{k=0}^c\mu(p^k)p^k ,由于 k > 1 k>1 μ ( p k ) = 0 \mu(p^k)=0 ,所以只考虑 k = 0 , 1 k=0,1 ,那么 f ( x ) = x c ( 1 x ) f(x)=x^c(1-x)
  • x = p y , g c d ( p , y ) = 1 x=py,gcd(p,y)=1 ,根据积性函数定义 f ( x ) = f ( p ) f ( y ) f(x)=f(p)f(y)
  • x = p y , g c d ( p , y ) ̸ = 1 x=py,gcd(p,y)\not=1 时,我们将 y y 中的 p p 提出,得到 x = p c + 1 y p c x=p^{c+1}\frac{y}{p^c} ,那么此时两个就互质了,所以 f ( x ) = f ( y p c ) f ( p c + 1 ) f(x)=f(\frac{y}{p^c})f(p^{c+1}) ,其中 p c y p^c|y

代码就十分好写了,同样也可以过第一题:

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int M=1e7+10,P=1e6+10;
const ll Mod=20101009;
ll prime[P],cnt;bool vis[M];
ll F[M],c[M],p[M],f[M],inv_2;
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;
}
void init(ll n){
	F[1]=1;
	for(int i=1;i<=n;i++)p[i]=f[i]=1;
	for(ll i=2;i<=n;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			F[i]=(i-(i*i%Mod)+Mod)%Mod;
			c[i]=1;f[i]=i;p[i]=i;
		}
		for(ll j=1,v;j<=cnt&&i*prime[j]<=n;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];
				F[v]=F[v/p[v]]*((p[v]-p[v]*f[v]%Mod+Mod)%Mod)%Mod;
				break;
			}
			F[v]=(F[i]*F[prime[j]])%Mod;
			c[v]=1;f[v]=prime[j];p[v]=prime[j];
		}
	}
	
	for(int i=2;i<=n;i++)F[i]=(F[i]+F[i-1])%Mod;
}
ll S(ll a){if(a>=Mod)a%=Mod;return ((a*(a+1)%Mod)*inv_2)%Mod;}
ll calc(ll L,ll R){return ((F[R]-F[L-1])%Mod+Mod)%Mod;}
ll solve(ll n,ll m){
	if(n>m)swap(n,m);
	init(n);
	inv_2=fpow(2,Mod-2);
	ll ans=0;
	for(ll i=1,j;i<=n;i=j+1){
		j=min(n/(n/i),m/(m/i));
		ans=(ans+S(n/i)*S(m/i)%Mod*calc(i,j)%Mod)%Mod;
	}
	return ans;
}
ll n,m;
int main(){
	scanf("%lld%lld",&n,&m);
	printf("%lld\n",solve(n,m));
	return 0;
}

51Nod 1238 最小公倍数之和V3

还是一样的问题,只不过 n = m 1 0 10 n=m\leq10^{10} ,只询问一次。

此时就不能线性筛了,必须要做到线性以下的求法,那么就是杜教筛了。

而前面化简的式子,若 f ( x ) = x d x μ ( d ) d f(x)=x\sum_{d|x}\mu(d)d 能杜教筛出,那么就可以用之前的方法做,但是这并不好实现反正博主不会的啦QWQ

所以我们考虑,在这个时候重新变换:

= d = 1 n d i = 1 n d j = 1 n d i j [ g c d ( i , j ) = 1 ] =\sum_{d=1}^nd\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}ij[gcd(i,j)=1]

我们可以先来看个式子:
i = 1 n j = 1 i [ g c d ( i , j ) = 1 ] i j \sum_{i=1}^{n}\sum_{j=1}^i[gcd(i,j)=1]ij

我们知道 φ ( i ) \varphi(i) 表示 1 i 1 1\sim i-1 中与 i i 互质的个数,而容易得知, 1 i 1 1\sim i-1 中与 i 1 i-1 互质的数的和为 i φ ( i ) 2 \frac{i\varphi(i)}{2}

简单证明:因为对于一个数 d i 1 d\leq i-1 ,如果它与 i i 互质,根据欧几里得算法, i d i-d 也与 i i 互质,那么这一对互质的和就为 i i ,总共有 φ ( i ) \varphi(i) 个互质,总和就是 i φ ( i ) i\varphi(i) ,但是 d , i d d,i-d i d , d i-d,d 算了两次,所以再除以2就是答案了,其中1要特殊考虑。

所以上面的那个式子可以写成:
= i = 1 n i j = 1 i j [ g c d ( i , j ) = 1 ] = i = 1 n i i φ ( i ) + [ i = 1 ] 2 =\sum_{i=1}^ni\sum_{j=1}^ij[gcd(i,j)=1]\\ =\sum_{i=1}^ni\frac{i\varphi(i)+[i=1]}{2}

那么我们看原式,就可以写成:
= d = 1 n d ( 2 × ( i = 1 n d i i φ ( i ) + [ i = 1 ] 2 ) 1 ) = d = 1 n d ( i = 1 n d i 2 φ ( i ) ) =\sum_{d=1}^nd\left(2\times\left(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i\frac{i\varphi(i)+[i=1]}{2}\right)-1\right)\\ =\sum_{d=1}^nd\left(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}{i^2\varphi(i)}\right)

因为原式后半部分可以写成:

i = 1 n d i ( j = 1 i j [ g c d ( i , j ) = 1 ] + j = i + 1 n d j [ g c d ( i , j ) = 1 ] ) \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i\left(\sum_{j=1}^{i}j[gcd(i,j)=1]+\sum_{j=i+1}^{\lfloor\frac{n}{d}\rfloor}j[gcd(i,j)=1]\right)

而后面两部分就想一个正方形,边长为 n d \lfloor\frac{n}{d}\rfloor ,沿着对角线剪开一样,是对称的,所以取其中一个乘以 2 2 即可。

详细来说,原式可以变成:
d = 1 n d ( 2 × ( i = 1 n d j = 1 i i j ) i = 1 n d i 2 ) \sum_{d=1}^nd \left(2\times \left(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^iij\right)-\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i^2\right)
因为 ( i , j ) , ( j , i ) (i,j),(j,i) 会被算两次,所以乘以2,而 ( i , i ) (i,i) 只会被算一次所以减去,然后就可以用前面式子替换就可以得到,后面 d = 1 n i = 1 n d i 2 = n × ( n + 1 ) 2 \sum_{d=1}^n\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i^2=\frac{n\times(n+1)}{2} 减去 d = 1 n d i = 1 n d [ i = 1 ] = n × ( n + 1 ) 2 \sum_{d=1}^nd\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}[i=1]=\frac{n\times(n+1)}{2} 的刚好消掉。

那么原式就转换成了求:

d = 1 n d ( i = 1 n d i 2 φ ( i ) ) \sum_{d=1}^nd\left(\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}{i^2\varphi(i)}\right)

我们令 f ( x ) = x 2 φ ( x ) f(x)=x^2\varphi(x) ,然后令 g ( x ) = x 2 g(x)=x^2 ,容易得知( \bigotimes 为狄利克雷卷积):

f g ( n ) = d n f ( d ) g ( n d ) = d n d 2 φ ( d ) ( n d ) 2 = n 2 d n φ ( d ) f\bigotimes g(n)=\sum_{d|n}f(d)g(\frac{n}{d})=\sum_{d|n}d^2\varphi(d)(\frac{n}{d})^2=n^2\sum_{d|n}\varphi(d)

又因为 d n φ ( d ) = n \sum_{d|n}\varphi(d)=n ,所以令:

h ( n ) = f g ( n ) = n 3 h(n)=f\bigotimes g(n)=n^3

S ( n ) = i = 1 n f ( i ) S(n)=\sum_{i=1}^nf(i) ,因为 g ( 1 ) = 1 g(1)=1

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

S ( n ) = i = 1 n h ( i ) i = 2 n g ( i ) S ( n i ) S(n)=\sum_{i=1}^nh(i)-\sum_{i=2}^ng(i)S(\left\lfloor\frac{n}{i}\right\rfloor)

也就是:

S ( n ) = ( n × ( n + 1 ) 2 ) 2 i = 2 n i 2 S ( n i ) S(n)=\left(\frac{n\times(n+1)}{2}\right)^2-\sum_{i=2}^ni^2S(\left\lfloor\frac{n}{i}\right\rfloor)

i = 1 n i 2 = n × ( n + 1 ) × ( 2 n + 1 ) 6 \sum_{i=1}^ni^2=\frac{n\times(n+1)\times(2n+1)}{6} ,所以这个式子就很容易算了。

用杜教筛的方式先预处理 n 2 3 n^{\frac{2}{3}} 的答案,然后数论分块递归即可。

对于原式外面我们仍然数论分块求即可。

复杂度 O ( n 2 3 ) O(n^{\frac{2}{3}})

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e6+10,M=1e4+10;
const ll Mod=1e9+7;
ll prime[N],phi[N],cnt,n;
ll F[N],D[M],inv_2,inv_6;
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 &Rec(ll a){
	if(a<N) return F[a];
	else return D[n/a];
}
bool vis[N];
ll Sqr(ll a){if(a>=Mod)a%=Mod;return a*a%Mod;}
void init(int up){
	memset(F,-1,sizeof(F));
	memset(D,-1,sizeof(D));
	phi[1]=1;
	inv_2=fpow(2,Mod-2);
	inv_6=fpow(6,Mod-2);
	for(int i=2;i<up;i++){
		if(!vis[i]){
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for(int j=1,v;j<=cnt&&i*prime[j]<up;j++){
			v=i*prime[j];
			vis[v]=1;
			if(!(i%prime[j])){
				phi[v]=phi[i]*prime[j];
				break;
			}
			phi[v]=phi[i]*phi[prime[j]];
		}
	}
	F[0]=0;
	for(int i=1;i<up;i++)F[i]=(F[i-1]+phi[i]*Sqr(i)%Mod)%Mod;
}
ll S(ll a){if(a>=Mod)a%=Mod;return (a*(a+1)%Mod)*inv_2%Mod;}
ll S2(ll a){if(a>=Mod)a%=Mod;return (a*(a+1)%Mod*((a+a+1)%Mod)%Mod)*inv_6%Mod;}
ll S3(ll a){if(a>=Mod)a%=Mod;return Sqr(S(a));}
ll Sarea(ll L,ll R){return ((S(R)-S(L-1))%Mod+Mod)%Mod;}
ll S2area(ll L,ll R){return ((S2(R)-S2(L-1))%Mod+Mod)%Mod;}
ll calc(ll x){
	ll &ans=Rec(x);
	if(ans!=-1) return ans;
	ans=S3(x);
	for(ll i=2,j;i<=x;i=j+1){
		j=x/(x/i);
		(ans-=(S2area(i,j)*calc(x/i))%Mod)%=Mod;
	}
	return (ans+Mod)%Mod;
}
ll solve(){
	ll ans=0;
	for(ll i=1,j;i<=n;i=j+1){
		j=n/(n/i);
		(ans+=(Sarea(i,j)*calc(n/i))%Mod)%=Mod;
	}
	return ans;
}
int main(){
	scanf("%lld",&n);
	init(min(n+1,1ll*N));
	printf("%lld\n",solve());
	return 0;
} 

大佬的更好的讲解-by fwat Orz%%%【链接

另一种方法-by Imagine Orz%%%【链接


如果有错,或者有更好的方法,欢迎提出!(*`∀´*)ノ亻!

End

快要退役了,再努力搏一搏吧

猜你喜欢

转载自blog.csdn.net/VictoryCzt/article/details/85054670