欧拉函数
基础知识
定义:\(\varphi(n)\) 表示 \(n\) 以内与 \(n\) 互质的数的个数。
有:
\[n=\sum_{d|n}\varphi(d)
\]
\[\varphi({p_i}^{k_i})={p_i}^{k_i}-{p_i}^{k_i-1}
\]
\[\varphi(n)=n\times \prod_{i=1}^s \frac{p-1}{p}
\]
可以自己证一下,挺好玩的,若是不会可以看 OIWiKi。
由于是积性函数,由:
-
\(\varphi(1)=1\)
-
\(\varphi(p)=p-1,p\in prime\)
-
\(\varphi(p^k)=\varphi(p^{k-1})\times p\)
-
\(\varphi(i)=\varphi(p)\times \varphi(\frac{i}{p})\),其中 \(p\) 是 \(i\) 的最小质因子。
也就是说,只有在处理 \(\varphi(p^k)\) 这一项上和莫比乌斯函数不同。
那么线性筛代码也很好写了。
#include <stdio.h>
#define LL long long
using namespace std;
const int N=1e6+3;
inline LL rin()
{
LL s=0;
bool bj=false;
char c=getchar();
for(;(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')bj=true,c=getchar();
for(;c>='0'&&c<='9';c=getchar())s=(s<<1)+(s<<3)+(c^'0');
if(bj)s=-s;
return s;
}
bool pri[N];
int var[N];
int d[N];
int tail;
int main()
{
var[1]=1;
for(int i=2;i<N;i++)
{
if(!pri[i])d[++tail]=i,var[i]=i-1;
for(int j=1;j<=tail;j++)
{
int now=i*d[j];
if(now>=N)break;
pri[now]=true;
if(i%d[j]==0)
{
var[now]=var[i]*d[j];
break;
}
var[now]=var[i]*var[d[j]];
}
}
for(int T=rin();T;T--)printf("%d\n",var[rin()]);
return 0;
}
欧拉定理
前提:\(\gcd(a,m)=1\),结论:\(a^{\varphi(m)}\equiv 1\pmod m\)。
那么当模数是质数的时候,可以用这个定理来求逆元。
扩展欧拉定理
结论:
当 \(b\ge \varphi(p)\) 时,有:
\[a^b\pmod p=\begin{cases} a^ {\ b\mod \varphi (p)},\gcd(a,p)=1\\ a^{\ b\mod \varphi(p)+\varphi(p)},\gcd(a,p)\ne 1 \end{cases}
\]
那么很多情况下可以直接套用第二种情况,第一种情况也可以看作是 \((a,p)=1\) 时欧拉定理的运用。
练习
【模板】线性筛 varphi
【模板】扩展欧拉定理
定义方面的问题:要记住那个通式的前提是:\(b\ge \varphi(p)\)。
还有一个 版本。
上帝与集合的正确用法
保证了是质数,相比之下可能比模板题还板。
$$\texttt{Dirty Deeds Done Dirt Cheap}$$