数论总结


持续更新~~

本篇博客包含了本蒟蒻学的数论知识点\(qwq\)

需要有一定基础


欧几里得算法

欧几里得算法,用于计算两个整数的最大公约数

对于两个数\(a,b\),我们定义\(gcd(a,b)\)表示它们的最大公约数

为了比较快的求出最大公约数,有了以下引理:

\[gcd(a,b)=gcd(b,a\%b) \]

证明:

我们设\(a=xc,b=yc\)其中\(x,y\)互质

那么\(c\)自然就是\(a,b\)最大公约数

\(a\%b=(x-ky)c\)

此时我们发现\(x-ky,y\)互质,证明:

假设\(x-ky,y\)不互质,设\(y=np,x-ky=mp\)其中\(n,m\)互质

\(y=np\)代入\(x-ky=mp\)得:

\[x-knp=mp \]

\[x=p(kn+m) \]

那么我们发现此时\(x,y\)不互质,有公约数\(p\),与最上面的假设相反,所以\(x-ky,y\)互质

那么上文提及\(b=yc,a\%b=(x-ky)c\)

\(y,x-ky\)互质

所以\(b,a\%b\)的最大公约数为\(c\)

所以\(gcd(a,b)=gcd(b,a\%b)=c\)

#include<iostream>
#include<cstdio>
using namespace std;
int a,b;
int Get_gcd(int a,int b)
{
	return b?Get_gcd(b,a%b):a;
}
int main()
{
	scanf("%d%d",&a,&b);
	printf("gcd(%d,%d)=%d\n",a,b,Get_gcd(a,b));
	return 0;
}

扩展欧几里得算法

扩展欧几里得算法,一般用来求解不定方程,求解线性同余方程,求解模的逆元

引理:有一组\(x,y\)使得:\(gcd(a,b)=ax+by\)

证明:

\((1)\)、对于\(b=0\)的情况,\(gcd(a,b)=a\),那么此时\(x=1,y=0\)

\((2)\)、对于\(b!=0\)的情况,我们根据欧几里得算法设:

\[ax+by=gcd(a,b)=gcd(b,a\%b)=bx_2+a\%b \times y_2 \]

因为\(a\%b=a-a/b*b\)

所以上式变形为:

\[ax+by=bx_2+(a-a/b \times b)y_2 \]

\[ax+by=bx_2+ay_2-a/b \times by_2 \]

\[ax+by=ay_2+bx_2-a/b\times by_2 \]

\[ax+by=ay_2+b(x_2-a/b\times y_2) \]

那么我们发现每一层的情况都能由下一层递归得到,边界则为\(b=0\)

那么代码如下:

#include<iostream>
#include<cstdio>
using namespace std;
int a,b,x,y,X,Y;//最好不要用x1,y1,万能库会出错
void Exgcd(int a,int b)
{
	if(!b)
	{
		x=1;
		y=0;
		return;
	}
	Exgcd(b,a%b);
	X=y;
	Y=x-a/b*y;
	x=X;
	y=Y;
}
int main()
{
	printf("a,b=");
	scanf("%d%d",&a,&b);
	Exgcd(a,b);
	printf("gcd(%d,%d)=%da+%db",a,b,x,y);
	return 0;
}

欧拉定理

定理:若正整数\(a,n\)互质,则$$a^{φ(n)}≡1\ (mod\ n)$$

证明:

设集合\(X_1,X_2,……,X_{φ(n)}\)\(1\)\(n-1\)中与\(n\)互质的数

那么我们思考下列数的性质:

\[aX_1,aX_2,……,aX_{φ(n)} \]

\((1)\)、集合中任意两个数模\(n\)余数一定不同

证明(反证法):

假设有 $$aX_1≡aX_2\ (mod\ n)$$

那么必须存在

\[aX_1-aX_2≡0\ (mod\ n) \]

\[a(X_1-X_2)≡0\ (mod\ n) \]

但是我们发现\(a,n\)互质,而\(X_1-X_2\)\(n\)小,根据唯一分解定理可以得出上式不成立

于是我们得出结论:集合中任意两个数模\(n\)余数一定不同

\((2)\)、集合中任意数模\(n\)\(n\)互质

证明:

首先,\(a,n\)互质,\(X_1,n\)互质,那么容易得出\(aX_1,n\)互质,那么得到:

\[gcd(aX_1,n)=1 \]

运用欧几里得算法得到:

\[gcd(n,aX_1\%n)=1 \]

也就是\(aX_1\%n,n\)互质

于是就得到了集合中任意数模\(n\)\(n\)互质

那么对于下面集合

\[aX_1\%n,aX_2\%n,……,aX_{φ(n)}\%n \]

我们发现这个集合其实排序后就是:

\[X_1,X_2,……,X_{φ(n)} \]

因为那个集合数字满足取值范围在\(1\)\(n-1\)之间(模了\(n\)),并且每个数与\(n\)互质,且两两不同,并且有\(φ(n)\)个数(性质\(1\),性质\(2\)),这不正是上面这个集合的性质吗?

那么:

\[aX_1 \times aX_2 \times ……\times aX_{φ(n)}≡X_1 \times X_2 \times …… \times X_{φ(n)}\ (mod\ n) \]

变形:

\[(a^{φ(n)}-1)X_1 \times X_2 \times …… \times X_{φ(n)}≡0\ (mod\ n) \]

\(X_1 \times X_2 \times …… \times X_{φ(n)}\)\(n\)互质,那么说明

\[a^{φ(n)}-1≡0\ (mod\ n) \]

\[a^{φ(n)}≡1\ (mod\ n) \]

欧拉定理得证


费马小定理

定理:对于质数\(p\),任意整数\(a\),均满足:\(a^p≡a\ (mod\ p)\)

证明:

我们把式子稍微变形一下:

\[a^{p-1} \times a≡a\ (mod\ p) \]

\[a^{p-1}≡1\ (mod\ p) \]

根据欧拉定理得到:

\[a^{φ(p)}≡1\ (mod\ p) \]

由于\(p\)是质数,所以\(φ(p)=p-1\),那么上式变为:

\[a^{p-1}≡1\ (mod\ p) \]

于是变回:

\[a^p≡a\ (mod\ p) \]

费马小定理得证


乘法逆元

这个东西以前以为是个什么高级的东西。。。

定义:

如果 \(a\times x\equiv 1 \ (mod\ p)\)并且\(gcd(a,p)=1\)(a,p互质)的话,我们称\(x\)\(a\)在模\(p\)意义下的乘法逆元

求解乘法逆元方法\(1\):费马小定理

\(p\)满足是质数的时候,我们可以用费马小定理来求解乘法逆元

费马小定理(\(p\)为质数):

\[a^p\equiv a\ (mod\ p) \]

我们变形一下:

\[a\times a^{p-2}\equiv 1\ (mod\ p) \]

所以当\(p\)是质数的时候,\(a\)在模\(p\)意义下的乘法逆元为\(a^{p-2}\),套一个快速幂即可

这个方法对于单个查询,且\(p\)是质数的时候适用

方法\(2\):扩展欧几里得

我们首先观察一下式子:$$a\times x\equiv 1\ (mod\ p)$$

我们把它变一下也就是$$a\times x-y\times p=1$$

我们为了便于观看,把p用b代替,也就是:$$a\times x-b\times y=1$$

也就是说我们只要满足上面这个式子,那么\(x\)就是\(a\)在模\(b\)意义下的乘法逆元,同样的\(y\)就是\(b\)在模\(a\)意义下的乘法逆元

这个方法适用于单个查询

方法\(3\):线性算法

首先,我们知道$$1^{-1}\equiv 1\ (mod\ p)$$

我们假定\(p=k\times i+r(0<r<i<p)\)

那么我们把这个式子放在\((mod\ p)\)的意义下:$$k\times i+r\equiv 0\ (mod\ p)$$

两边都乘上\(i^{-1}\times r^{-1}\)得:$$k\times r{-1}+i\equiv 0\ (mod\ p)$$

\[i^{-1}\equiv -k\times r^{-1}\ (mod\ p) \]

\(k,r\)替换一下:$$i^{-1}\equiv -\left\lfloor\frac{p}{i}\right\rfloor \times (p\ mod\ i)^{-1}\ (mod\ p)$$

这样的话,我们就可以由前面的逆元推出后面的逆元了

这种方法适用于求一连串相邻数的逆元

例题:洛谷P3811

代码:

#include<iostream>
#include<cstdio>
#define int long long
#define N 3000000
using namespace std;
int n,p;
int inv[N];
signed main()
{
	scanf("%lld%lld",&n,&p);
	inv[1]=1;
	for(int i=2;i<=n;++i)
		inv[i]=((p-p/i)*inv[p%i])%p;
	for(int i=1;i<=n;++i)
		printf("%lld\n",inv[i]);
	return 0;
}

方法\(4\):线性算法\(2\)

以下式子都在模\(p\)意义下进行

我们先算出\(a_i\)的前缀积:$$s[i]=s[i-1]\times a_i$$

我们发现只要算出每一个前缀积的逆元\(t_i\),每一个\(a_i\)的逆元都好求了:$$a_i^{-1}=t_i\times s_{i-1}$$

那么怎么求每一个前缀积的逆元呢,我们可以先把\(t_n\)运用费马小定理求出来: $$t_n=s_n^{p-2}$$

再根据:$$t_i=t_{i+1}\times a_{i+1}$$

递推出所有的\(t\)

这个方法适用于求给出一串无规则的数的逆元

代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#define int long long
#define N 5000007
using namespace std;
int n,p,k;
int s[N],a[N],inv[N],inv_s[N];
int qpow(int a,int b)
{
	int ans=1,res=a;
	while(b)
	{
		if(b&1)
			ans=(ans*res)%p;
		res=(res*res)%p;
		b/=2;
	}
	return ans%p;
}
signed main()
{
	scanf("%lld%lld",&n,&p);
	s[0]=1;
	for(int i=1;i<=n;++i)
	{
		scanf("%lld",&a[i]);
		s[i]=(s[i-1]*a[i])%p;
	}
	inv_s[n]=qpow(s[n],p-2);
	for(int i=n-1;i>=1;--i)
		inv_s[i]=(inv_s[i+1]*a[i+1])%p;
	for(int i=n;i>=1;--i)
		inv[i]=(inv_s[i]*s[i-1])%p;
	for(int i=1;i<=n;++i)
		printf("%lld\n",inv[i]); 
	return 0;
}

拓展:求阶乘逆元

定义\(inv[i]\)\(i!\)的逆元

首先我们知道:$$inv[i+1]=\frac{1}{i+1!}$$

两边同时乘\(i+1\)得:$$inv[i+1]\times (i+1)=\frac{1}{i!}=inv[i]$$

所以我们只要先求出\(inv[n]\)然后往回递推出来就\(ok\)


欧拉函数

定义:

\(φ(n)\)表示\(1\)\(n\)中,与\(n\)互质的数的个数

特殊的\(φ(1)=1\)

\(φ(n)=n\times \prod\limits_{i=1}^k(1-\frac{1}{p_i})\),其中\(p_i\)表示\(n\)的质因数

证明:

因为每一个质因数\(p_i\)的倍数在\(n\)中都是均匀分布的,所以在\(n\)中会有\(n\times \frac{1}{p_i}\)\(p_i\)的倍数,那么其余的就是\(n\times (1-\frac{1}{p_i})\)个,每个质因数都是如此,那么最后不是所有质因数的倍数的自然就是与\(n\)互质的数,也就是\(n\times \prod\limits_{i=1}^k(1-\frac{1}{p_i})\)

积性函数

对于一个函数\(F(x)\),如果\(m,n\)互质,满足\(F(m)\times F(n)=F(m\times n)\)的话,这个函数叫做积性函数,如果\(m,n\)不互质,而是任意整数满足上式的话被叫做完全积性函数

性质:

\(1\)、当\(p\)为质数时,\(φ(p)=p-1\)

证明:。。。看看定义就知道吧

\(2\)、当\(p\)为质数时,\(φ(p^k)=p^k-p^{k-1}\)

证明:因为\(p\)为质数,所以:$$φ(pk)=pk\times (1-\frac{1}{p})$$

因为\(p^k\)只有\(p\)这一个质因数

括号去掉就是性质\(2\)

\(3\)、欧拉函数是积性函数但不是完全积性函数,对于\(m,n\)互质时,有\(φ(m)\times φ(n)=φ(m\times n)\)

\(4\)、当\(n>2\)时,\(φ(n)\)为偶数

证明:这个是有一个基本事实:\(gcd(n,p)=1,gcd(n,n-p)=1\),也就是说与\(n\)互质的数是成对出现的,所以\(φ(n)\)为偶数

\(5\)、对于小于\(n\)且与\(n\)互质的数,总和\(=φ(n)\times n/2\)

证明:上面已经说明了与\(n\)互质的数是成对出现的,每一对与\(n\)互质的数的平均数为\((p+n-p)/2\),也就是\(n/2\),一共有\(φ(n)\)个与\(n\)互质的数,所以总和为\(φ(n)\times n/2\)

\(6\)\(n=\sum\limits_{d|n}φ(d)\)

证明:设$$F(n)=\sum\limits_{d|n}φ(d)$$

对于互质的两个数\(m,n\):$$F(n)\times F(m)=\sum\limits_{i|m}φ(i)\times \sum\limits_{j|n}φ(j)$$

\[=φ(i_1)\times φ(j_1)+φ(i_1)\times φ(j_2)+\cdots +φ(i_{km})\times φ(j_{kn}) \]

因为欧拉函数是积性函数,而\(m,n\)互质,所以它们的所有因数都互质,所以得到:

\[φ(i_1\times j_1)+φ(i_1\times j_2)+\cdots +φ(i_{km}\times j_{kn}) \]

我们发现\(i_1\times j_1,i_1\times j_2,\cdots,i_{km}\times j_{kn}\)刚好就是\(m\times n\)的所有因数,所以得到:

\[\sum\limits_{k|m\times n} φ(k) \]

\[=F(m\times n) \]

所以我们证明了\(F(n)\)函数是积性函数

那么对于任何一个质数\(p\),我们要求\(F(p^k)\)的时候怎么求呢?

因为\(p^k\)的因数只有\(1,p,p^2,\cdots,p^k\),我们运用性质\(2\)

\[F(p^k) \]

\[=φ(1)+φ(p)+\cdots+φ(p^k) \]

\[=1+(p-1)+(p^2-p)+\cdots+(p^k-p^{k-1}) \]

\[=p^k \]

我们把\(n\)进行质因数分解,会得到很多质数,而它们的\(F\)函数就等于本身,所以:

\[F(n)=F(p_1^{k_1})\times F(p_2^{k_2})\times \cdots \times F(p_m^{k_m}) \]

\[=p_1^{k_1}\times p_2^{k_2}\times \cdots \times p_m^{k_m} \]

\[=n \]

求欧拉函数

单个:\(2-\sqrt n\)扫一遍就好了,素数怎么求这个就怎么求

要是求<=n所有数的欧拉函数呢?

埃拉托斯特尼筛求欧拉函数 \(O(n(log(n))(loglogn))\)

就是普通的找质数,把倍数都筛一遍(质因数的贡献)

void Euler(int n)
{
    for(int i=1;i<=n;++i) 
        phi[i]=i;
    for (int i=2;i<=n;++i)
        if (phi[i]==i)//i是质数
            for (int j=i;j<=n;j+=i)//把i的倍数筛一遍
                phi[j]=phi[j]/i*(i-1);
}

欧拉筛求欧拉函数 \(O(n)\)

先来了解一下欧拉筛

for(int i=2;i<=n;++i)
{
    if(!vis[i])//不是目前找到的素数的倍数 
        prime[cnt++]=i;//找到素数~ 
    for(int j=0;j<cnt&&i*prime[j]<=n;++j)
    {
        vis[i*prime[j]]=true;//找到的素数的倍数不访问 
        if(i%prime[j]==0) 
            break;//关键!!!! 
    }
}

很多人对 \(if(i\% prime[j]==0)\) 这一句都不太理解

找到一种很好的解释:
\(i\)\(prime[j]\)的倍数时,\(i=k∗prime[j]\),如果继续运算 \(j+1\)\(i∗prime[j+1]=prime[j]∗k∗prime[j+1]\)
这里\(prime[j]\)是最小的素因子,当\(i=k∗prime[j+1]\)时会重复
这里是利用最小素因子优化,使得欧拉筛达到了优秀的线性\(O(n)\)

下面正式求欧拉函数啦

void Euler(int n)
{
    phi[1]=1;//1要特判 
    for (int i=2;i<=n;i++)
    {
        if(flag[i]==0)//这代表i是质数 
        {
            prime[++num]=i;
            phi[i]=i-1;
        }
        for (int j=1;j<=num&&prime[j]*i<=n;j++)//经典的欧拉筛写法 
        {
            flag[i*prime[j]]=1;//先把这个合数标记掉 
            if (i%prime[j]==0)
            {
                phi[i*prime[j]]=phi[i]*prime[j];//若prime[j]是i的质因子,则根据计算公式,i已经包括i*prime[j]的所有质因子 
               break;//经典欧拉筛的核心语句,这样能保证每个数只会被自己最小的因子筛掉一次 
            }
            else 
                phi[i*prime[j]]=phi[i]*phi[prime[j]];//利用了欧拉函数是个积性函数的性质 
        }
    }
}

狄利克雷卷积

数论函数

数论函数亦称算术函数,一类重要的函数,指定义在正整数集上的实值或复值函数,更一般地,也可把数论函数看做是某一整数集上定义的函数

运算

定义两个数论函数的加法为逐项相加,即: $$(f+g)(n)=f(n)+g(n)$$

定义两个数论函数的乘法为这个数与每一项相乘,即: $$(x\times f)(n)=x\times f(n)$$

狄利克雷卷积

如下:$$t(n)=\sum\limits_{i|n}f(i)g(\frac{n}{i})$$

性质

\(1\)、交换律: $$f\times g=g\times f$$

\(2\)、结合律:$$(f\times g)\times h=f\times (g\times h)$$

\(3\)、分配率:$$(f+g)\times h=f\times h+g\times h$$

\(4\)\(t\)是积性函数

证明:设\(n=a\times b\),且\(gcd(a,b)=1\)

\[t(n)=\sum\limits_{i|a,j|b} f(i\times j)g(\frac{a}{i} \times \frac{b}{j}) \]

\[=\sum\limits_{i|a,j|b} f(i)g(\frac{a}{i})f(j)g(\frac{b}{j}) \]

\[=\sum\limits_{i|a} f(i)g(\frac{a}{i}) \sum\limits_{j|b} f(j)g(\frac{b}{j}) \]

\[=t(a)\times t(b) \]


莫比乌斯反演

对于两个函数\(F(n)\)\(f(n)\)如果满足:$$F(n)=\sum\limits_{d|n}f(d)$$

通过莫比乌斯反演会得到:$$f(n)=\sum\limits_{d|n} \mu (d)F(\frac{n}{d})$$

为什么呢?我们先来了解一下上面的\(\mu\)函数

莫比乌斯函数

\[\mu (n) \]

\(1\)、当\(n=1\)时,\(\mu (1)=1\)

\(2\)、当\(n>=2\)

\((1)\)\(d=\prod\limits_{i=1}^k p_i\) \(p_i\)为互异素数,\(\mu (n)=(-1)^k\)

\((2)\)、当上面\(p_i\)不互异时,也就是至少有大于等于一次方的质因数时,\(\mu (n)=0\)

所以莫比乌斯函数的性质就出来了:$$\sum\limits_{d|n} \mu (d)=[n=1]$$

证明莫比乌斯反演

因为性质$$\sum\limits_{d|n} \mu (d)=[n=1]$$

化成狄利克雷卷积形式为:$$\mu \times I=\epsilon$$

那么我们把莫比乌斯反演的式子拿过来:$$F(n)=\sum\limits_{d|n} f(d)$$

化成狄利克雷卷积形式为:$$F=f\times I$$

两边都乘上\(\mu\)为:$$F\times \mu =f\times I\times \mu$$

也就是:$$F\times \mu =f\times \epsilon$$

也就是:$$f=\mu \times F$$

化回来就是:$$f(n)=\sum\limits_{d|n} \mu (d)\times F(\frac{n}{d})$$


整除分块

这是一个很神奇的方法,可以把很多数论中的\(O(n)\)的优秀复杂度优化成更优秀的\(O(\sqrt n)\)

例如下面的式子:$$\sum\limits_{i=1}^n \left\lfloor \frac{n}{i} \right\rfloor $$

我们本来是可以直接一次循环\(O(n)\)算出的,但是有些题目可能会卡,所以更优秀的算法出来了

我们发现对于一部分连串的\(i\)\(\frac{n}{i}\)会相同

例如当\(n=11\)时,\(i=6,7,8,9,10,11\)的时候\(\frac{n}{i}\)都等于\(1\)

所以我们可以分一块一块来做

下面是代码:

int Get(int x)
{
	int ans=0;
	for(int i=1,j;i<=x;i=j+1)
	{
		j=x/(x/i);
		ans+=(x/i)*(j-i+1);
	}
	return ans;
}

据说上面的复杂度是\(O(\sqrt n)\),然而我太弱了,不会证,姑且用着吧~~~


莫比乌斯函数与欧拉函数的关系

\[\frac{φ(n)}{n}=\sum\limits_{d|n} \frac{\mu (d)}{d} \]

其实应该放在上面的,但是学习没有学全面,现在才学到

首先,我们知道:$$\sum\limits_{d|n} φ(d)=n$$

变形:$$\sum\limits_{d|n} φ(d)=id(n)$$

变成狄利克雷卷积形式就是:$$φ\times I=id$$

我们两边都乘上\(\mu\):$$φ\times I\times \mu=id\times \mu$$

我们知道\(I\times \mu =\epsilon\),带入:$$φ=id\times \mu$$

化回来:$$φ(n)=\sum\limits_{d|n} \mu (d) id(\frac{n}{d})$$

\[φ(n)=\sum\limits_{d|n} \mu (d) \frac{n}{d} \]

\[\frac{φ(n)}{n}=\sum\limits_{d|n} \frac{\mu (d)}{d} \]


杜教筛

假设我们要求一个式子,其中\(f\)为积性函数:$$S(n)=\sum\limits_{i=1}^n f(i)$$

那么我们构造两个积性函数:$$h=g\times f$$

展开:$$h(n)=\sum\limits_{d|n} g(d)\times f(\frac{n}{d})$$

两边都求和:$$\sum\limits_{i=1}^n h(i)=\sum\limits_{i=1}^n \sum\limits_{d|i} g(d) \times f(\frac{i}{d})$$

套路的换枚举项:$$\sum\limits_{i=1}^n h(i)=\sum\limits_{i=1}^n \sum\limits_{d=1}^n [d|i]\ g(d) \times f(\frac{i}{d})$$

\(d\)\([d|i]\)消除:$$\sum\limits_{i=1}^n h(i)=\sum\limits_{d=1}^n \sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor} g(d) \times f(i)$$

\[\sum\limits_{i=1}^n h(i)=\sum\limits_{d=1}^n g(d) \sum\limits_{i=1}^{\left\lfloor \frac{n}{d} \right\rfloor} f(i) \]

我们把\(S(n)=\sum\limits_{i=1}^n f(i)\)带入上式:$$\sum\limits_{i=1}^n h(i)=\sum\limits_{d=1}^n g(d) S(\left\lfloor \frac{n}{d} \right\rfloor)$$

那么我们现在把\(d=1\)的提出来:$$g(1)S(n)=\sum\limits_{i=1}^n h(i)-\sum\limits_{d=2}^n g(d)S(\left\lfloor \frac{n}{d} \right\rfloor)$$

那么我们现在就求出用杜教筛的式子了

我们举个例子:

当我们要求下式的时候:$$\sum\limits_{i=1}^n \mu(i)$$

我们设:$$S(n)=\sum\limits_{i=1}^n \mu(i)$$

那么我们就要求\(S(n)\)

我们就要构造出两个积性函数\(h,g\),而我们也要使得\(h,g\)容易求出

我们知道:$$\mu \times I=\epsilon$$

那么我们就把\(g=I\)\(h=\epsilon\)

这样带入上式的话,为:$$S(n)=1-\sum\limits_{d=2}^n S(\left\lfloor \frac{n}{d} \right\rfloor)$$

那么我们知道后面半部分可以用整除分块,那么我们预处理出\(n^{\frac{2}{3}}\)\(S\),然后记忆化求出剩余的就行(可以具体看下面代码理解)

再举个例子

假如要求:$$\sum\limits_{i=1}^n φ(i)$$

那么构造函数就会想到:$$φ\times I=id$$

那么带入就会得:$$S(n)=\frac{n\times (1+n)}{2}-\sum\limits_{d=2}^n S(\left\lfloor \frac{n}{d} \right\rfloor)$$

下面给出上面两个例子的代码

美滋滋的代码时间~~~

#include<iostream>
#include<cstdio>
#include<tr1/unordered_map>
#define N 5500007
#define ll long long
#define il inline
#define re register
#pragma GCC optimize(2)
#pragma GCC optimize(3)
using namespace std;
int T,n,cnt;
int sum1[N],prime[N],mu[N],phi[N];
ll sum2[N];
bool isp[N];
tr1::unordered_map<int,int> map_mu;
tr1::unordered_map<int,ll> map_phi; 
il int read()
{
    re int x=0,f=1; re char c=getchar();
    while(c<'0'||c>'9') {if(c=='-') f=-1;c=getchar();}
    while(c>='0'&&c<='9') x=x*10+c-48,c=getchar();
    return x*f;
}
il void Get(int x)
{
	mu[1]=phi[1]=1;
	for(re int i=2;i<=x;++i)
	{
		if(!isp[i])
		{
			prime[++cnt]=i;
			mu[i]=-1;
			phi[i]=i-1;
		}
		for(re int j=1;j<=cnt&&(i*prime[j])<=x;++j)
		{
			isp[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			else
			{
				phi[i*prime[j]]=phi[i]*phi[prime[j]];
				mu[i*prime[j]]=-mu[i];
			}
		}
	}
	for(re int i=1;i<=x;++i)
		sum1[i]=sum1[i-1]+mu[i],sum2[i]=sum2[i-1]+phi[i];
}
il int Ans_mu(ll x)
{
	if(x<=5500000)
		return sum1[x];
	if(map_mu[x])
		return map_mu[x];
	int ans=1;
	for(re int l=2,r;l<=x;l=r+1)
	{
		r=x/(x/l);
		ans-=(r-l+1)*Ans_mu(x/l);
	}
	return map_mu[x]=ans;
}
il ll Ans_phi(ll x)
{
	if(x<=5500000)
		return sum2[x];
	if(map_phi[x])
		return map_phi[x];
	ll ans=(x*(1+x))/2;
	for(re ll l=2,r;l<=x;l=r+1)
	{
		r=x/(x/l);
		ans-=(r-l+1)*Ans_phi(x/l);
	}
	return map_phi[x]=ans;
}
int main()
{
	T=read();
	Get(5500000);
	while(T--)
	{
		n=read();
		printf("%lld %d\n",Ans_phi(n),Ans_mu(n));
	}
	return 0;
}

再拓展一个例子:

我们要求:$$\sum\limits_{i=1}^n i\times φ(i)$$

我们设:$$S(n)=\sum\limits_{i=1}^n i\times φ(i)$$

那么我们发现不好怎么配\(g,h\)函数,这个时候怎么办呢,我们把\(f\)化为卷积形式:$$\sum\limits_{d|n} (d\times φ(d))g(\frac{n}{d})$$

那么我们发现\(d\)有点讨厌,那就要想办法消去,我们发现如果\(g\)函数为\(id\)函数的时候,\(d\)可以互相约去,也就是:$$\sum\limits_{d|n} n\times φ(d)$$

发现\(n\)\(d\)无关,可以提出来:$$n\sum\limits_{d|n} φ(d)$$

而我们发现后面一部分就是\(n\),所以式子就是:$$n^2$$

那么带回去之后就是:$$S(n)=\sum\limits_{i=1}^n i^2 -\sum\limits_{d=2}^n d\times S(\left\lfloor \frac{n}{d} \right\rfloor)$$

我们发现只要能算出平方和的话就可以求出来了

那么平方和怎么算呢?

\[1^2+2^2+3^2+\cdots +n^2 \]

因为\(n^2=n(n+1)-n\),那么得到:$$1\times 2 -1+2\times 3-2+3\times 4-3+\cdots +n(n+1)-n$$

移项得:$$1\times 2+2\times 3+3\times 4+\cdots +n(n+1)-(1+2+3+\cdots +n)$$

因为\(n(n+1)=\frac{n(n+1)(n+2)-(n-1)n(n+1)}{3}\),所以前一部分互相消去变成:$$\frac{n(n+1)(n+2)}{3}$$

后一部分为:$$-\frac{(1+n)n}{2}$$

原式为:$$\frac{n(n+1)(n+2)}{3}-\frac{(1+n)n}{2}$$

通分:$$\frac{2n(n+1)(n+2)}{6}-\frac{3n(1+n)}{6}$$

\[=\frac{n(1+n)(2n+1)}{6} \]

大功告成~~~


posted @ 2019-02-17 18:34  模拟退火  阅读(823)  评论(0编辑  收藏  举报