定义

欧拉函数 $\varphi(n)$表示小于等于$n$的正整数中与$n$互质的数的数目。

性质

1、积性函数(证明)。

2、$\varphi(1)=1$(显然)

3、对于质数$n$,$\varphi(n)=n-1$(显然)

4、对于质数的幂$n=p^k$(其中$p$为质数,$k$为正整数),$\varphi(n)=p^{k-1}\cdot(p-1)$

证明:

归纳法,在$k=1$时显然成立,假设当$k$为$k-1$时成立,那么对于将$1,2,...p^k$中每一个数表示为$x\cdot p^{k-1}+d$,其中$0\leq x<p$,$1\leq d\leq p^{k-1}$,若某一个数对$\varphi(n=p^k)$有贡献,则其$d$的部分一定不含质因子$p$,因而一定对$\varphi(p^{k-1})$有贡献,所以,恰好每一个对$\varphi(p^{k-1})$有贡献的数都会对$\varphi(p^k)$有$p$次贡献,所以有$\varphi(p^k)= \varphi(p^{k-1}) \times p=p^{k-2}\times (p-1)\times p=p^{k-1}\times (p-1)$,得证。

计算

不妨设$n=\prod p_i^{t_i}$,其中$p_i$是质数,$t_i$为正整数。

则有$\varphi(n)=n \prod \frac {p_i-1} {p_i}$。

特别的,$\varphi(1)=1$。

证明的话,利用积性函数的性质和性质四组合即可证明。

反演

利用欧拉函数本身定义和其一条重要性质$$n=\sum\limits_{d|n} \varphi(d)$$

(其证明涉及到了我的知识盲区)

在莫比乌斯反演中,我们常利用莫比乌斯函数的性质把$$\sum\limits_{x=1}^{n} \sum\limits_{y=1}^{n} [gcd(x,y)=1]$$

转化为$$\sum\limits_{x=1}^n \sum\limits_{y=1}^n \sum\limits_{d|x,d|y} \mu(d)$$

然后进一步改变枚举项

那么类似的,我们也可以利用欧拉函数的定义将其转化$$\sum\limits_{x=1}^{n} \sum\limits_{y=1}^{n} [gcd(x,y)=1]\Rightarrow 2( \sum\limits_{i=1}^{n} \varphi(i))-1$$

这里两道利用欧拉函数进行反演的例题

1、BZOJ4804 欧拉心算

$T$组数据,给定$n$求$\sum\limits_{x=1}^{n} \sum\limits_{y=1}^{n} \varphi(gcd(x,y))$,$(T\leq 5000,n\leq 10^7)$

和上文的方法类似

$$\sum\limits_{x=1}^{n} \sum\limits_{y=1}^{n} \varphi(gcd(x,y))$$

$$\Downarrow$$

$$\sum\limits_{d=1}^{n} \varphi(d)\sum\limits_{x=1}^{\lfloor \frac nd \rfloor}\sum\limits_{y=1}^{\lfloor \frac nd \rfloor}[gcd(x,y)=1]$$

$$\Downarrow$$

$$\sum\limits_{d=1}^{n} \varphi(d)(2( \sum\limits_{i=1}^{\lfloor \frac nd \rfloor} \varphi(i))-1)$$这样只需要对前半部分数论分块,对后半部分线性筛预处理前缀和即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 10000010
using namespace std;
int read(){
int nm=0,fh=1;char cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
int n,m,p[M],ph[M],tot,T;
LL G[M];
bool vis[M];
void init(){
memset(vis,true,sizeof(vis));
ph[1]=G[1]=1,vis[1]=false;
for(int i=2;i<M;i++){
if(vis[i]) ph[i]=i-1,p[++tot]=i;
for(int j=1;j<=tot&&p[j]*i<M;j++){
int num=p[j]*i; vis[num]=false;
if(i%p[j]==0){ph[num]=ph[i]*p[j];break;}
ph[num]=ph[i]*ph[p[j]];
}
G[i]=G[i-1]+ph[i];
}
}
LL calc(){
int now=1,RS,D;
LL ans=0;
while(now<=n){
D=n/now,RS=n/D;
ans+=(G[RS]-G[now-1])*((G[D]<<1)-1);
now=RS+1;
}
return ans;
}
void write(LL x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
int main(){
init(),T=read();
while(T--) n=read(),write(calc()),putchar('\n');
return 0;
}

2、BZOJ3518 点组计数(权限题)

求$n\times m$方格点阵上任选三点共线的方案数(不同顺序属于同种方案),$n,m\leq 10^5$

将水平和竖直的直线单独取出计算

对于倾斜的直线,枚举共线的三点的两端的横坐标只差$x$与纵坐标之差$y$。

他们中间的方格点的数量就应该是$gcd(x,y)-1$,接着再把$-1$单独取出计算,再利用$n=\sum_{d|n} \varphi(d)$这一条性质交换枚举项进行计算即可。$$ans1=n\cdot C_m^3 + m\cdot C_n^3$$

$$ans2=2\sum\limits_{i=1}^n\sum\limits_{j=1}^m(gcd(i,j)-1)(n-i)(m-j)$$

$$ans2=2(t1-t2),t1=\sum\limits_{i=1}^n\sum\limits_{j=1}^m gcd(i,j)(n-i)(m-j),t2=\frac{n(n-1)}{2}\cdot \frac{m(m-1)}{2}$$

$$n=\sum\limits_{d|n} \varphi(d)$$

$$\Downarrow$$

$$\sum\limits_{i=1}^n\sum\limits_{j=1}^mgcd(i,j)=\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sum\limits_{d|i,d|j}\varphi(d)=\sum\limits_{d=1}^{min(n,m)}\varphi(d) \lfloor \frac nd \rfloor \lfloor \frac md \rfloor$$

$$\Downarrow$$

$$t1=\sum\limits_{d=1}^n\varphi(d)\sum\limits_{i=1}^{\lfloor \frac n d \rfloor}(n-i\times d)\sum\limits_{j=1}^{\lfloor \frac m d\rfloor} (m-j\times d)$$仍然只需要常规的数论分块求解即可。

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 50020
#define mod 1000000007
using namespace std;
LL read(){
LL nm=0,fh=1;char cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
LL n,m,p[M],ph[M],tot,ans,MAXN;
bool vis[M];
void init(){
memset(vis,true,sizeof(vis));
ph[1]=1,vis[1]=false,MAXN=min(n,m);
for(LL i=2;i<=max(n,m);i++){
if(vis[i]) ph[i]=i-1,p[++tot]=i;
for(LL j=1;j<=tot&&p[j]*i<MAXN;j++){
LL num=p[j]*i; vis[num]=false;
if(i%p[j]==0){ph[num]=ph[i]*p[j];break;}
ph[num]=ph[i]*ph[p[j]];
}
}
}
LL ari(LL fs,LL ed,LL tot){return ((fs+ed)*(tot)/2)%mod;}
LL calc(){
LL res=0;
for(LL d=1;d<MAXN;d++){
LL t1=ari(n-d,n-((n-1)/d)*d,(n-1)/d);
LL t2=ari(m-d,m-((m-1)/d)*d,(m-1)/d);
res+=(t1*t2%mod)*ph[d]%mod;
}
return (res<<1)%mod;
}
int main(){
n=read(),m=read(),init(),ans=calc();
ans+=mod-(2*((n-1)*n/2)*((m-1)*m/2))%mod;
if(n>=3) ans+=m*((n*(n-1)*(n-2)/6)%mod)%mod;
if(m>=3) ans+=n*((m*(m-1)*(m-2)/6)%mod)%mod;
printf("%lld\n",ans%mod);
return 0;
}

欧拉函数的另一个主流的应用就是在取模方面,即欧拉定理

$$x^{\varphi(P)}\equiv 1(mod\space P),(gcd(x,P)=1)$$

最经典的题目大概就是[BZOJ3884]上帝与集合的正确用法[BZOJ4869][2017六省联考]相逢是问候了。

主要思路就是“幂次幂”,利用欧拉函数的性质,证得不断对于一个数求欧拉函数,即$\varphi(\varphi(...n...))$,只需$2log(n)$次直到1,随后一直不变。

简单证明一下,对于大于$1$的整数$n$:

若$n$为奇数,则其中必然含有一个奇质因数,因此$\varphi(n)$为偶数。

若$n$为偶数,则其中必然含有质因数$2$,因此$\varphi(n)\leq \frac n2$。

我也就不写具体的题解了,还是就把代码放上吧

[BZOJ3884]上帝与集合的正确用法

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 500200
#define N 10000
using namespace std;
LL read(){
LL nm=0,fh=1;char cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
LL n,T,c[M],p[M],pri[M],ph[M],tmp,mod,m,cnt;
bool vis[M];
LL qpow(LL x,LL qs,LL md){
LL fin=1;
while(qs){
if(qs&1) fin=fin*x%md;
qs>>=1,x=x*x%md;
}
return fin;
}
void init(){
memset(vis,true,sizeof(vis)),ph[1]=1,cnt=0;
for(LL i=2;i<M;i++){
if(vis[i]) pri[++cnt]=i,ph[i]=i-1;
for(LL j=1;pri[j]*i<M&&j<=cnt;j++){
LL num=pri[j]*i; vis[num]=false;
if(i%pri[j]==0){ph[num]=ph[i]*pri[j];break;}
ph[num]=ph[i]*ph[pri[j]];
}
}
}
LL PHI(LL x){
LL fin=x,rem=x;
if(x<M) return ph[x];
for(LL j=1;j<=cnt&&pri[j]<=rem;j++){
if(rem%pri[j]==0) fin/=pri[j],fin*=(pri[j]-1);
while(rem%pri[j]==0) rem/=pri[j];
}
if(rem>1) fin/=rem,fin*=(rem-1);
return fin;
}
LL calc(){
for(p[tmp=0]=mod;p[tmp]>1;tmp++) p[tmp+1]=PHI(p[tmp]);
p[++tmp]=1; LL res=2;
for(LL i=tmp;i;i--){
res%=p[i],res+=p[i];
res=qpow(2,res,p[i-1]);
}
return res;
}
int main(){
init(),T=read();
while(T--) mod=read(),printf("%lld\n",calc());
return 0;
}

[BZOJ4869][2017六省联考]相逢是问候

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LL long long
#define M 500200
#define N 10000
using namespace std;
LL read(){
LL nm=0,fh=1;char cw=getchar();
for(;!isdigit(cw);cw=getchar()) if(cw=='-') fh=-fh;
for(;isdigit(cw);cw=getchar()) nm=nm*10+(cw-'0');
return nm*fh;
}
LL n,T,c[M],p[M],f[M],tpe,L,R,tg[M],pre[M];
LL cnt,tk[M],P[1000],isp[M],pri[M],ph[M],Mi[10010][70][2],tmp,mod,m;
bool vis[M];
LL find(LL x){return f[x]==x?x:f[x]=find(f[x]);}
LL qpow(LL x,LL qs,LL md){
LL fin=1;
while(qs){
if(qs&1) fin=fin*x%md;
qs>>=1,x=x*x%md;
}
return fin;
}
LL mul(LL kd,LL tim){return Mi[tim%N][kd][0]*Mi[tim/N][kd][1]%P[kd];}
void add(LL pos,LL x){for(LL k=pos;k<=n;k+=(k&(-k))) (c[k]+=x)%=mod;}
LL sum(LL pos){
LL tot=0ll;
for(LL k=pos;k>0;k-=(k&-k)) (tot+=c[k]+mod)%=mod;
return tot;
}
void init(){
memset(vis,true,sizeof(vis)),ph[1]=1,cnt=0;
for(LL i=2;i<M;i++){
if(vis[i]) pri[++cnt]=i,ph[i]=i-1;
for(LL j=1;pri[j]*i<M&&j<=cnt;j++){
LL num=pri[j]*i; vis[num]=false;
if(i%pri[j]==0){ph[num]=ph[i]*pri[j];break;}
ph[num]=ph[i]*ph[pri[j]];
}
}
}
LL PHI(LL x){
LL fin=x,rem=x;
if(x<M){return ph[x];}
for(LL j=1;j<=cnt&&pri[j]<=rem;j++){
if(rem%pri[j]==0) fin/=pri[j],fin*=(pri[j]-1);
while(rem%pri[j]==0) rem/=pri[j];
}
if(rem>1) fin/=rem,fin*=(rem-1);
return fin;
}
LL calc(LL kd,LL now){
for(LL i=kd;i;i--){
if(now>=P[i]) now=now%P[i]+P[i];
now=mul(i-1,now);
if(!now) now=P[i-1];
}
return now;
}
int main(){
n=read(),T=read(),mod=read(),m=read();
for(LL i=1;i<=n;i++) f[i]=i,p[i]=read(),pre[i]=p[i],add(i,p[i]);
P[0]=mod,init(),f[n+1]=n+1;
for(tmp=0;P[tmp]>1;tmp++) P[tmp+1]=PHI(P[tmp]);
P[++tmp]=1;
for(LL kd=0;kd<=tmp;kd++){
Mi[0][kd][0]=Mi[0][kd][1]=1%P[kd];
for(LL i=1;i<=N;i++) Mi[i][kd][0]=Mi[i-1][kd][0]*m%P[kd];
for(LL i=1;i<=N;i++) Mi[i][kd][1]=Mi[i-1][kd][1]*Mi[N][kd][0]%P[kd];
}
while(T--){
tpe=read(),L=read(),R=read();
if(tpe){printf("%lld\n",(sum(R)-sum(L-1)+mod)%mod);continue;}
for(LL now=find(L);now<=R;now=find(now+1)){
tg[now]++;LL num=calc(tg[now],p[now]),dt;
dt=num+mod-pre[now],add(now,dt%mod);
if(tg[now]==tmp) f[now]=f[find(now+1)];
pre[now]=num;
}
}
return 0;
}

  

欧拉函数(汇总&例题)的更多相关文章

  1. UVA10200-Prime Time/HDU2161-Primes,例题讲解,牛逼的费马小定理和欧拉函数判素数。

                                                    10200 - Prime Time 此题极坑(本菜太弱),鉴定完毕,9遍过. 题意:很简单的求一个区间 ...

  2. POJ2154 Color【 polya定理+欧拉函数优化】(三个例题)

    由于这是第一天去实现polya题,所以由易到难,先来个铺垫题(假设读者是看过课件的,不然可能会对有些“显然”的地方会看不懂): 一:POJ1286 Necklace of Beads :有三种颜色,问 ...

  3. 紫书 例题 10-7 UVa 10820 (欧拉函数)

    这道题要找二元组(x, y) 满足1 <= x, y <= n 且x与y互素 那么我就可以假设x < y, 设这时答案为f(n) 那么答案就为2 * f(n) +1(x与y反过来就乘 ...

  4. 欧拉函数 - HDU1286

    欧拉函数的作用: 有[1,2.....n]这样一个集合,f(n)=这个集合中与n互质的元素的个数.欧拉函数描述了一些列与这个f(n)有关的一些性质,如下: 1.令p为一个素数,n = p ^ k,则 ...

  5. poj3090欧拉函数求和

    E - (例题)欧拉函数求和 Crawling in process... Crawling failed Time Limit:1000MS     Memory Limit:65536KB     ...

  6. lightOJ1370 欧拉函数性质

    D - (例题)欧拉函数性质 Crawling in process... Crawling failed Time Limit:2000MS     Memory Limit:32768KB     ...

  7. bzo4802 欧拉函数 miller_rabin pollard_rho

    欧拉函数 Time Limit: 5 Sec  Memory Limit: 256 MBSubmit: 1112  Solved: 418[Submit][Status][Discuss] Descr ...

  8. 浅谈欧拉函数 By cellur925

    1.某神犇Blog 学了三遍的 欧拉函数φ--DEADFISH7 2.我要做一些补充o(* ̄▽ ̄*)o $φ(1)=1$: 公式有两种形式,一种有太多除法,实际可能会慢些.通用 对于任意$n$> ...

  9. [学习笔记]约数&欧拉函数

    约数 一.概念 约数,又称因数.整数a除以整数b(b≠0) 除得的商正好是整数而没有余数,我们就说a能被b整除,或b能整除a.a称为b的倍数,b称为a的约数. 二.性质 1.整数唯一分解 1)定义 对 ...

随机推荐

  1. Window系统下MongoDB安装及远程访问

    1.编辑mongodb 安装文件夹bin\mongod.cfg 把bindIP 改为 127.0.0.1, 192.168.1.180(局域网IP) 可以参考https://blog.csdn.net ...

  2. Android 新建一个类,在src新建一个类,使继承自活动

    一:先新建一个包 右键src,新建包: 二:包中新建类 右建包,新建类,将超类改为andorid.app.Activity

  3. [SCOI2009]生日礼物(尺取法)

    Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 2201  Solved: 1186[Submit][Status][Discuss] Descript ...

  4. DP(正解完全背包+容斥)

    DP Time Limit:10000MS     Memory Limit:165888KB     64bit IO Format:%lld & %llu Submit Status De ...

  5. elasticsearch从入门到出门-04-入门的几个需求练手

    第一个分析需求:计算每个tag下的商品数量 GET /ecommerce/product/_search{  "aggs": {    "group_by_tags&qu ...

  6. Linux修改网络配置

    修改:/etc/sysconfig/network-scripts/ifcfg-eth0 重启网卡/etc/rc.d/init.d/network restart

  7. eclipse安装Activiti Designer插件(转载:http://blog.csdn.net/qq_33547950/article/details/54926435)

    为了完成毕业设计,需要学习Activiti.万事开头难,果然刚开始就遇到了问题.<Activiti实战>和视频教程里提供的安装Activiti Designer插件方法(即下文方法一)不能 ...

  8. php基本语法与函数

    1.标记与注释 <?php 代码 ?> 用/*  */注释一段代码,  用 // 注释一行代码   /**    */文档注释 注意:若php下面只有php代码没有别的代码,那么最好不要加 ...

  9. 每天一个Linux命令(23)chmod命令

        chmod命令用来变更文件或目录的权限. 在UNIX系统家族里,文件或目录权限的控制分别以读取.写入.执行3种一般权限来区分,另有3种特殊权限可供运用.用户可以使用chmod指令去变更文件与目 ...

  10. 每天一个Linux命令(12)more命令

    more命令是一个基于vi编辑器文本过滤器,它以全屏幕的方式按页显示文本文件的内容,支持vi中的关键字定位操作. 该命令一次显示一屏文本,满屏后停下来,并且在屏幕的底部出现一个提示信息,给出至今己显示 ...