数论推式子

P3327 [SDOI2015]约数个数和

题意:给定n、m,求 ∑ i = 1 n ∑ j = 1 m d ( i j ) \sum_{i=1}^n\sum_{j=1}^md(ij) i=1nj=1md(ij)

推导
1、有个结论: d ( i j ) = ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] d(ij)=\sum_{x|i}\sum_{y|j}[gcd(x,y)=1] d(ij)=xiyj[gcd(x,y)=1]
∑ i = 1 n ∑ j = 1 m d ( i j ) = ∑ i = 1 n ∑ j = 1 m ∑ x ∣ i ∑ y ∣ j [ g c d ( x , y ) = 1 ] \sum_{i=1}^n\sum_{j=1}^m d(ij)=\sum_{i=1}^n\sum_{j=1}^m \sum_{x|i}\sum_{y|j}[gcd(x,y)=1] i=1nj=1md(ij)=i=1nj=1mxiyj[gcd(x,y)=1]

2、枚举倍数
∑ x = 1 n ∑ y = 1 m ∑ x ∣ i n ∑ y ∣ j m [ g c d ( x , y ) = 1 ] \sum_{x=1}^n\sum_{y=1}^m\sum_{x|i}^n\sum_{y|j}^m[gcd(x,y)=1] x=1ny=1mxinyjm[gcd(x,y)=1]

3、化简并且利用莫比乌斯函数的性质换元
∑ x = 1 n ∑ y = 1 m ⌊ n x ⌋ ⌊ m x ⌋ ∑ d ∣ g c d ( x , y ) μ ( d ) \sum_{x=1}^n\sum_{y=1}^m {\lfloor \frac nx \rfloor} {\lfloor \frac mx\rfloor} \sum_{d|gcd(x,y)} \mu(d) x=1ny=1mxnxmdgcd(x,y)μ(d)

4、枚举d,并且设n ∑ x = 1 n ∑ y = 1 m ⌊ n x ⌋ ⌊ m x ⌋ ∑ d = 1 n μ ( d ) [ d ∣ x 且 d ∣ y ] \sum_{x=1}^n\sum_{y=1}^m {\lfloor \frac nx \rfloor} {\lfloor \frac mx\rfloor} \sum_{d=1}^n \mu(d)[d|x 且 d|y] x=1ny=1mxnxmd=1nμ(d)[dxdy]

5、仔细观察这个式子,其实是可以再继续化简的, [ d ∣ x ] 、 [ d ∣ y ] [d|x]、[d|y] [dx][dy]中枚举的是d倍数,因此可以化简为:
∑ d = 1 n μ ( d ) ∑ x = 1 n ⌊ n x ⌋ [ d ∣ x ] ∑ y = 1 m ⌊ m x ⌋ [ d ∣ y ] \sum_{d=1}^n \mu(d) \sum_{x=1}^{n} {\lfloor \frac nx \rfloor}[d|x] \sum_{y=1}^m{\lfloor \frac mx \rfloor}[d|y] d=1nμ(d)x=1nxn[dx]y=1mxm[dy]

∑ d = 1 n μ ( d ) ∑ i = 1 ⌊ n d ⌋ ⌊ n d i ⌋ ∑ j = 1 ⌊ m d ⌋ ⌊ m d j ⌋ \sum_{d=1}^n \mu(d) \sum_{i=1}^{\lfloor \frac nd \rfloor} {\lfloor \frac n{di} \rfloor} \sum_{j=1}^{\lfloor \frac md \rfloor}{\lfloor \frac m{dj} \rfloor} d=1nμ(d)i=1dndinj=1dmdjm

6、然后我们设 f ( x ) = ∑ i = 1 x ⌊ x i ⌋ f(x)=\sum_{i=1}^x {\lfloor \frac xi \rfloor} f(x)=i=1xix,原式就可以化简为
∑ d = 1 n μ ( d ) f ( n d ) f ( m d ) \sum_{d=1}^n \mu(d) f(\frac nd) f(\frac md) d=1nμ(d)f(dn)f(dm)

7、同时 f ( x ) f(x) f(x)恰好是[1,x]中每个数的约数的个数之和,因此可以线性筛处理d[i],然后作前缀和即可

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (abs(d) < 1e-8)
using namespace std;
const int maxn=5e4+5,INF=0x3f3f3f3f;
const int mod=1e9+7;

const int N=5e4;
int prime[maxn],visit[maxn],mu[maxn];
ll f[maxn];
int d[maxn],num[maxn],cnt;

void init()
{
	mu[1]=1,d[1]=1,cnt=0;
	for(int i=2;i<=N;++i)
	{
		if(!visit[i])
			prime[++cnt]=i,mu[i]=-1,d[i]=2,num[i]=1;
		for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
		{
			visit[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				d[i*prime[j]]=d[i]/(num[i]+1)*(num[i]+2);
				num[i*prime[j]]=num[i]+1;
				break;
			}
			d[i*prime[j]]=d[i]*2;
			num[i*prime[j]]=1;
			mu[i*prime[j]]=-mu[i];
		}
	}
	
	for(int i=1;i<=N;++i)
	{
		f[i]=f[i-1]+d[i];
		mu[i]+=mu[i-1]; 
	}	
}

int main()
{
	init();
	int T,n,m;
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		if(n>m)
			swap(n,m);
		int l=1,r;
		ll ans=0;
		while(l<=n)
		{
			r=min(n/(n/l),m/(m/l));
			ans+=(mu[r]-mu[l-1])*f[n/l]*f[m/l];
			l=r+1;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

The 2019 ACM-ICPC China Shannxi Provincial Programming Contest B - Product

题意:给定n、m、p,求公式模p的值
∏ i = 1 n ∏ j = 1 n ∏ k = 1 n m g c d ( i , j ) [ k ∣ g c d ( i , j ) ] \prod_{i=1}^n\prod_{j=1}^n\prod_{k=1}^n m^{gcd(i,j)[k|gcd(i,j)]} i=1nj=1nk=1nmgcd(i,j)[kgcd(i,j)]

推导
1、先只考虑指数
∑ i = 1 n ∑ j = 1 n ∑ k = 1 n g c d ( i , j ) [ k ∣ g c d ( i , j ) ] \sum_{i=1}^n \sum_{j=1}^n\sum_{k=1}^ngcd(i,j)[k|gcd(i,j)] i=1nj=1nk=1ngcd(i,j)[kgcd(i,j)]

2、这里k枚举了gcd(i,j)的因子,因此先把k消掉,原式就转变为
∑ i = 1 n ∑ j = 1 n g c d ( i , j ) d ( g c d ( i , j ) ) \sum_{i=1}^n \sum_{j=1}^ngcd(i,j)d(gcd(i,j)) i=1nj=1ngcd(i,j)d(gcd(i,j))

3、然后我们把gcd(i,j)取出来,枚举这个gcd(i,j)
∑ x = 1 n x d ( x ) ∑ i = 1 n ∑ j = 1 n [ g c d ( i , j ) = x ] \sum_{x=1}^n xd(x) \sum_{i=1}^n\sum_{j=1}^n[gcd(i,j)=x] x=1nxd(x)i=1nj=1n[gcd(i,j)=x]

4、后半部分,就 i , j i,j i,j 相当于在枚举x的倍数 i , j 走遍了x的倍数 ,可以化简为
∑ x = 1 n x d ( x ) ∑ i = 1 ⌊ n x ⌋ ∑ j = 1 ⌊ n x ⌋ [ g c d ( i , j ) = 1 ] \sum_{x=1}^n xd(x) \sum_{i=1}^{\lfloor \frac nx \rfloor}\sum_{j=1}^{\lfloor \frac nx \rfloor}[gcd(i,j)=1] x=1nxd(x)i=1xnj=1xn[gcd(i,j)=1]

5、后面部分是一个跟欧拉函数相关的式子,可以直接化简

∑ x = 1 n x d ( x ) ( 2 ∑ i = 1 ⌊ n x ⌋ φ ( i ) − 1 ) \sum_{x=1}^n xd(x) (2\sum_{i=1}^{\lfloor \frac nx \rfloor}\varphi(i)-1) x=1nxd(x)(2i=1xnφ(i)1)

6、看到这个 ⌊ n x ⌋ \lfloor \frac nx\rfloor xn就知道要分块了,对于左边部分 ∑ x = 1 n x d ( x ) \sum_{x=1}^n xd(x) x=1nxd(x),还是需要做一些优化才能在 n 很大的时候求解

∑ x = 1 n x d ( x ) = ∑ x = 1 n x ∑ d ∣ x 1 \sum_{x=1}^n xd(x)=\sum_{x=1}^nx\sum_{d|x}1 x=1nxd(x)=x=1nxdx1

换向枚举,枚举约数,改为枚举倍数
∑ d = 1 n ∑ d ∣ x n x \sum_{d=1}^{n} \sum_{d|x}^n x d=1ndxnx

既然我们枚举的x是d的倍数,那么显然可以化简为:
∑ d = 1 n ∑ t = 1 ⌊ n x ⌋ d t = ∑ d = 1 n d ∑ t = 1 ⌊ n x ⌋ t \sum_{d=1}^n\sum_{t=1}^{\lfloor \frac nx \rfloor} dt=\sum_{d=1}^n d\sum_{t=1}^{\lfloor \frac nx \rfloor} t d=1nt=1xndt=d=1ndt=1xnt

总结
1、我们所求的原式的指数就等于:
∑ x = 1 n x d ( x ) ( 2 ∑ i = 1 ⌊ n x ⌋ φ ( i ) − 1 ) \sum_{x=1}^n xd(x) (2\sum_{i=1}^{\lfloor \frac nx \rfloor}\varphi(i)-1) x=1nxd(x)(2i=1xnφ(i)1)

2、首先我们在[1,n]的范围内分块,左边用推得的公式求前缀和,右边用杜教筛求欧拉函数前缀和
3、然后我们在求 ∑ x = 1 n x d ( x ) \sum_{x=1}^n xd(x) x=1nxd(x)这个式子的时候,也就是在求 ∑ d = 1 n d ∑ t = 1 ⌊ n x ⌋ t \sum_{d=1}^n d\sum_{t=1}^{\lfloor \frac nx \rfloor} t d=1ndt=1xnt这个式子的后,还是要在[1,n]的范围内做分块

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (abs(d) < 1e-8)
using namespace std;
const int maxn=6e6+5,INF=0x3f3f3f3f;
int mod=1e9+7;

int add(int &x,int y)
{
	if(y<0)
		x+=y;
	else
		x=x+y-mod;
	if(x<0)
		x+=mod;
}

int abss(int x)
{
	if(x<0)
		x+=mod;
	return x;
}

int qpow(int base,int n,int mod)
{
	int ret=1;
	while(n)
	{
		if(n&1)
			ret=1ll*ret*base%mod;
		base=1ll*base*base%mod;
		n>>=1;
	}
	return ret;
}

const int N=6e6;
int prime[maxn],visit[maxn],d[maxn],num[maxn],phi[maxn],cnt;

void init()
{
	phi[1]=1,d[1]=1,cnt=0;
	for(int i=2;i<=N;++i)
	{
		if(!visit[i])	
			prime[++cnt]=i,d[i]=2,num[i]=1,phi[i]=i-1;
		for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
		{
			visit[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				d[i*prime[j]]=d[i]/(num[i]+1)*(num[i]+2);
				num[i*prime[j]]=num[i]+1;
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*phi[prime[j]];
			d[i*prime[j]]=d[i]*2;
			num[i*prime[j]]=1;
		}
	}
	
	for(int i=1;i<=N;++i)
	{
		d[i]=1ll*d[i]*i%mod;
		add(d[i],d[i-1]);
		add(phi[i],phi[i-1]);
	}
}

int pre_x(int n)
{
	return 1ll*(1+n)*n/2%mod;
} 

unordered_map<int,int> md,mphi;

int pre_sum(int n)
{
	if(n<=N)
		return d[n];
	if(md[n])
		return md[n];
	int ans=0,l=1,r;
	while(l<=n)
	{
		r=n/(n/l);
		add(ans,1ll*(pre_x(r)-pre_x(l-1))*pre_x(n/l)%mod);
		l=r+1;
	}
	return md[n]=ans;
}

int pre_phi(int n)
{
	if(n<=N)
		return phi[n];
	if(mphi[n])
		return mphi[n];
	int ans=pre_x(n);
	int l=2,r;
	while(l<=n)
	{
		r=n/(n/l);
		add(ans,-1ll*(r-l+1)*pre_phi(n/l)%mod);
		l=r+1;
	}
	return mphi[n]=ans;
}

int main()
{
	int n,m,p;
	scanf("%d%d%d",&n,&m,&p);
	mod=p-1;
	init();
	int ans=0,l=1,r;
	while(l<=n)
	{
		r=n/(n/l);
		add(ans,1ll*abss(pre_sum(r)-pre_sum(l-1))%mod*(2ll*pre_phi(n/l)-1)%mod);
		ans%=mod;
		l=r+1;
	}
	printf("%d\n",qpow(m,ans,p));
	return 0;
}

2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛 huntian oy HDU -6706

问题类别 杜教筛 算法类别 数论
其他知识点 来源 HDU-6706

Problem Description
One day, Master oy created a new function to celebrate his becoming a ‘huntian’ in majsoul.

f ( n , a , b ) = ∑ i = 1 n ∑ j = 1 i g c d ( i a − j a , i b − j b ) [ g c d ( i , j ) = 1 ] % ( 1 0 9 + 7 ) f(n,a,b)=\sum_{i=1}^n \sum_{j=1}^i gcd(i^a−j^a,i^b−j^b)[gcd(i,j)=1]\%(10^9+7) f(n,a,b)=i=1nj=1igcd(iaja,ibjb)[gcd(i,j)=1]%(109+7)

Given n, a and b, Master oy wanted Newbie jj who was still a ‘chuxin’ to answer the value of f(n,a,b).

Input
There are multiple test cases.
The first line contains an integer T, indicating the number of test cases.
For each test case, there are three positive integers n, a and b which are separated by spaces. It’s guaranteed that a and b are coprime.

1 ≤ n , a , b ≤ 1 0 9 1≤n,a,b≤10^9 1n,a,b109

T = 1 0 4 T=10^4 T=104, but there are only 10 test cases that n is over 1 0 6 10^6 106.

Output
For each test case, an integer in one line representing your answer.

Sample Input
2
1 2 3
100 2 3

Sample Output
0
101542

题意:求解 f ( n , a , b ) = ∑ i = 1 n ∑ j = 1 i g c d ( i a − j a , i b − j b ) [ g c d ( i , j ) = 1 ] f(n,a,b)=\sum_{i=1}^n \sum_{j=1}^i gcd(i^a−j^a,i^b−j^b)[gcd(i,j)=1] f(n,a,b)=i=1nj=1igcd(iaja,ibjb)[gcd(i,j)=1]

思路:打表可得 g c d ( i a − j a , i b − j b ) = i − j gcd(i^a−j^a,i^b−j^b)=i-j gcd(iaja,ibjb)=ij
原式化简为 ∑ i = 1 n ∑ j = 1 i ( i − j ) [ g c d ( i , j ) = 1 ] \sum_{i=1}^n \sum_{j=1}^i (i-j)[gcd(i,j)=1] i=1nj=1i(ij)[gcd(i,j)=1]
然后分成两部分:

∑ i = 1 n ∑ j = 1 i i [ g c d ( i , j ) = 1 ] − ∑ i = 1 n ∑ j = 1 i j [ g c d ( i , j ) = 1 ] \sum_{i=1}^n \sum_{j=1}^i i[gcd(i,j)=1]-\sum_{i=1}^n \sum_{j=1}^i j[gcd(i,j)=1] i=1nj=1ii[gcd(i,j)=1]i=1nj=1ij[gcd(i,j)=1]

左边部分显然就是: ∑ i = 1 n i φ ( i ) \sum_{i=1}^n i\varphi(i) i=1niφ(i)

主要简化右边部分: ∑ i = 1 n ∑ j = 1 i j [ g c d ( i , j ) = 1 ] \sum_{i=1}^n \sum_{j=1}^i j[gcd(i,j)=1] i=1nj=1ij[gcd(i,j)=1]

推导过程

∑ i = 1 n ∑ j = 1 i j ∑ d ∣ g c d ( i , j ) u ( d ) \sum_{i=1}^n\sum_{j=1}^i j\sum_{d|gcd(i,j)}u(d) i=1nj=1ijdgcd(i,j)u(d)

∑ i = 1 n ∑ d ∣ i u ( d ) ∑ j = 1 i j [ d ∣ j ] \sum_{i=1}^n\sum_{d|i}u(d)\sum_{j=1}^{i}j[d|j] i=1ndiu(d)j=1ij[dj]

∑ i = 1 n ∑ d ∣ i u ( d ) ∑ j = 1 ⌊ i d ⌋ j d \sum_{i=1}^n\sum_{d|i}u(d)\sum_{j=1}^{\lfloor \frac id \rfloor}jd i=1ndiu(d)j=1dijd

∑ i = 1 n ∑ d ∣ i u ( d ) d ( 1 + ⌊ i d ⌋ ) ⌊ i d ⌋ 2 \sum_{i=1}^n\sum_{d|i}u(d)d \frac {(1+{\lfloor \frac id \rfloor}){\lfloor \frac id \rfloor}}{2} i=1ndiu(d)d2(1+di)di

∑ i = 1 n i 2 ∑ d ∣ i u ( d ) ( 1 + ⌊ i d ⌋ ) \sum_{i=1}^n\frac i2 \sum_{d|i}u(d)(1+\lfloor \frac id\rfloor) i=1n2idiu(d)(1+di)

∑ i = 1 n ( i 2 ∑ d ∣ i u ( d ) + i 2 φ ( i ) ) \sum_{i=1}^n(\frac i2 \sum_{d|i}u(d)+\frac i2\varphi(i)) i=1n(2idiu(d)+2iφ(i))

∑ i = 1 n i   φ ( i ) 2 + ∑ i = 1 n i [ i = 1 ] 2 \sum_{i=1}^n \frac{i\ \varphi(i)}{2}+\sum_{i=1}^n\frac {i[i=1]}{2} i=1n2i φ(i)+i=1n2i[i=1]

题目条件告诉我们n是大于等于1的,因此右边部分就是 1 2 \frac 12 21

所以总的式子合起来就是:

∑ i = 1 n i φ ( i ) − ∑ i = 1 n i   φ ( i ) 2 − 1 2 \sum_{i=1}^n i\varphi(i)-\sum_{i=1}^n \frac{i\ \varphi(i)}{2}-\frac 12 i=1niφ(i)i=1n2i φ(i)21
最终所求即:
∑ i = 1 n i   φ ( i ) 2 − 1 2 \sum_{i=1}^n \frac{i\ \varphi(i)}{2}-\frac 12 i=1n2i φ(i)21

求积性函数前缀和我们可以使用杜教筛: h = f ∗ g h=f*g h=fg
我们设 f ( d ) = d φ ( d ) f(d)=d\varphi(d) f(d)=dφ(d),显然我们卷上id函数就可以凑成h
h = ∑ d ∣ n d φ ( d ) n d = ∑ d ∣ n φ ( d ) n = n 2 h=\sum_{d|n}d\varphi(d) \frac nd=\sum_{d|n}\varphi(d)n=n^2 h=dndφ(d)dn=dnφ(d)n=n2

利用杜教筛的公式(公式其实不用记,手推一遍也就1分钟的事情 ):
g ( 1 ) S ( n ) = ∑ i = 1 n h ( i ) − ∑ d = 2 n g ( d ) S ( ⌊ n d ⌋ ) g(1)S(n)=\sum_{i=1}^n h(i)-\sum_{d=2}^n g(d)S(\lfloor \frac nd \rfloor) g(1)S(n)=i=1nh(i)d=2ng(d)S(dn)
并根据推得的g、h函数化简
S ( n ) = ∑ i = 1 n i 2 − ∑ d = 2 n d × S ( ⌊ n d ⌋ ) S(n)=\sum_{i=1}^n i^2-\sum_{d=2}^n d\times S(\lfloor \frac nd \rfloor) S(n)=i=1ni2d=2nd×S(dn)

这样就做完了

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (abs(d) < 1e-8)
using namespace std;
const int mod=1e9+7;

int t;
int n,a,b;
ll inv2,inv6;

int qpow(int base,int n,int mod)
{
    int ret=1;
    while(n)
    {
        if(n&1)
            ret=1ll*ret*base%mod;
        base=1ll*base*base%mod;
        n>>=1;
    }
    return ret;
}

const int N=2e6;
int prime[N+10],phi[N+10],visit[N+10];
int cnt;

void init()
{
    cnt=0,phi[1]=1;
    for(int i=2;i<=N;++i)
    {
        if(!visit[i])
            prime[++cnt]=i,phi[i]=i-1;
        for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
        {
            visit[i*prime[j]]=1;
            if(i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];
                break;
            }
            phi[i*prime[j]]=phi[i]*phi[prime[j]];
        }
    } 
    for(int i=1;i<=N;++i)
    {
        phi[i]=1ll*phi[i]*i%mod;
        phi[i]=(phi[i]+phi[i-1])%mod;
    }
}

unordered_map<int,int> mphi;

int pre_x3(int n)
{
    return 1ll*n*(n+1)%mod*(2*n+1)%mod*inv6%mod;
}

int pre_phi(int n)
{
    if(n<=N)
        return phi[n];
    if(mphi[n])
        return mphi[n];
    
    int ans=pre_x3(n);
    int l=2,r;
    while(l<=n)
    {
        r=n/(n/l);
        ans=(1ll*ans-1ll*pre_phi(n/l)*(r-l+1)%mod*(l+r)%mod*inv2%mod+mod)%mod;
        l=r+1;
    }
    return mphi[n]=ans;
}

int abss(int x)
{
    if(x<0)
        x+=mod;
    return x;
}

int main()
{
    inv2=qpow(2,mod-2,mod);
    inv6=qpow(6,mod-2,mod);
    init();
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%d%d",&n,&a,&b);
        int ans=abss(1ll*pre_phi(n)*inv2%mod-inv2)%mod;
        printf("%d\n",ans);        
    }
    return 0;
}

你可能感兴趣的:(数论)