欧拉函数

题目描述


题解

首先,我们关注到这一题最重要的一点是保证所有的a,i,x,l,ra,i,x,l,ra,i,x,l,r均随机生成。
对于操作111,每次询问的区间和大小期望大概是na4≈5×108\frac{na}{4}\approx 5\times 10^84na​≈5×108,区间的和。
如果我们暴力算欧拉函数大概是O(5×108log⁡5×108≈4152.3)O(\sqrt{\frac{5\times 10^8}{\log 5\times 10^8}}\approx 4152.3)O(log5×1085×108​​≈4152.3)的,对于q=105q=10^5q=105,应该也勉强能过。
由于总和是随机的,所以应该也不需要所有质数都跑完,会更快一点。
关键是操作222,对于乘法我们又该怎样统计。
由于随机生成,所以我们可以猜测每个数所拥有的大于303030的质因子个数应该比较少,每个数大概期望有1.051.051.05个。
故我们很快可以想到将小于303030的质数贡献与大于303030的质数贡献分别进行处理。

对于小于303030的质数,由于个数比较小,我们可以考虑用线段树单独维护每个质因子的出现次数。
由于欧拉函数是积性函数,所以我们显然可以对于单个质因子分别统计欧拉函数值,最后乘起来。
询问222查询时就直接查询区间内这部分质数出现了多少个,计算该质数贡献的欧拉函数就行了,大概是O(10log⁡n)O\left(10\log\,n\right)O(10logn)的。

对于大于303030的质数,由于本身就比较多,相同质因子的应该也比较分散。
对于一个数的质因子ppp,如果它前面有数也存在ppp的质因子,那么它的贡献时ppp,否则是p−1p-1p−1。
对于前面是否存在数有质因子ppp,显然我们只需要看离它最近的一个ppp是不是在我们查询的区间范围内。
我们在查询到它的时候可以在前面的ppp的位置放上一个pp−1\frac{p}{p-1}p−1p​,在它原来的位置就放p−1p-1p−1,查询左边界的后缀积,显然只会在包含前面的哪个位置时它的贡献才会是ppp,否则其贡献为p−1p-1p−1。
这种技巧我们应该是在前面的题中见到过得,但我懒得找了。
但如果我们真的一个一个去查询的话显然太慢了,每一个都得拿一个数据结构维护,我们不妨考虑分块。
对于块内的点,如果它们不存在大于303030的公共质因子,显然它们之间是独立的,我们完全可以将它们维护的这个贡献给放在一起。
如果同一个块内两个数有着相同的质因子p−1p-1p−1,显然后面那一个是不可能产生p−1p-1p−1的贡献的,我们就将这个整块的贡献乘上p(p−1)p(p-1)p(p−1),再在前一个数的前一个相同质因子位置上放上pp−1\frac{p}{p-1}p−1p​就行了。
这样的话,我们对于一个整块就只需要维护一个数据结构了,这个数据结构采用树状数组就行了。
对于散块的点,我们需要知道的是它们前面是否有与它相同的质因子的数,这个数既可能来自整块的数,也有了能来自散块的数。
散块的数就直接将它们大于303030的质因子记录下来就行了,对于整块,我们可以去记录一下整块的数关于大于303030的每个质数的前缀和,通过差分找到我们现在的这个质数是否出现。
由于我们的修改次数是比较少的,我们可以在每次修改后暴力修正修改的这个质数的前缀和。
同时修改时对于整块我们可能会影响它自身与它相同质因子的后面最近的点关于整块数据结构内的贡献。
可以用setsetset维护它后面的点是哪一个,然后暴力在数据结构上更改。
这样就很容易计算出整块与散块的贡献了,与小于303030质数的贡献乘在一起就行了。

记我们进行了mmm次000类操作,有PPP个质数,SSS为块长,时间复杂度O(nSP+m(nS+10log⁡n)+q(10log⁡n+S+nSlog⁡n)⩾O(10(m+q)log⁡n+qnlog⁡n))O\left(\frac{n}{S}P+m(\frac{n}{S}+10\log\,n)+q(10\log\,n+S+\frac{n}{S}\log\,n)\geqslant O\left(10(m+q)\log\,n+q\sqrt{n\log\,n}\right)\right)O(Sn​P+m(Sn​+10logn)+q(10logn+S+Sn​logn)⩾O(10(m+q)logn+qnlogn​)),显然可以过。

源码

有点卡常。

#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize("Ofast")
#include<bits/stdc++.h>
using namespace std;
#define MAXN 50005
#define MAXM 500005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL;
typedef long double ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int mod=1e5+3;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=20000;
const int n1=400;
const int orG=3,ivG=332748118;
const long double Pi=acos(-1.0);
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
char gc(){static char buf[1000000],*p1=buf,*p2=buf;return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;}
#define getchar gc
char obuf[1<<22],*opt=obuf+(1<<22);
void pc(const int&ch){*--opt=ch;}
#define putchar pc
template<typename _T>
void read(_T &x){_T f=1;x=0;char s=getchar();while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}x*=f;
}
template<typename _T>
void print(_T x){putchar('\n');while(x>9){putchar((x%10)|'0');x/=10;}putchar(x|'0');}
int gcd(int a,int b){return !b?a:gcd(b,a%b);}
int add(int x,int y,int p){return x+y<p?x+y:x+y-p;}
void Add(int &x,int y,int p){x=add(x,y,p);}
int qkpow(int a,int s,int p){int t=1;while(s){if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s>>=1;}return t;}
const int M=255;
int n,q,a[MAXN],prime[MAXN],cntp,ff[MAXN],sta[MAXN],stak,tur[MAXN];
int block[MAXN],L[MAXN],R[MAXN],summ[MAXN],cnt[M][5005],ans[MAXN*2],tott;
int head[MAXN],nxt[MAXN*10],val[MAXN*10],tot;
set<int>s[MAXN];
set<int>::iterator it;
bool oula[MAXN],vis[MAXN];
void init(){for(int i=2;i<=4e4;i++){if(!oula[i]){prime[++cntp]=i,tur[i]=cntp;}for(int j=1;j<=cntp&&1ll*prime[j]*i<=4e4;j++){oula[i*prime[j]]=1;if(i%prime[j]==0)break;}}ff[1]=1;for(int i=2;i<=4e4;i++)ff[i]=1ll*(mo-mo/i)*ff[mo%i]%mo;
}
void work(int id){head[id]=0;int now=a[id];for(int i=1;i<=cntp&&1ll*prime[i]*prime[i]<=now;i++){if(now%prime[i])continue;if(i>10){val[++tot]=prime[i];nxt[tot]=head[id];head[id]=tot;}while(now%prime[i]==0)now/=prime[i];}if(now>prime[10]){val[++tot]=now;nxt[tot]=head[id];head[id]=tot;}
}
class BitTree{private:int tr[MAXN];public:void insert(int pos,int aw){while(pos<=n)tr[pos]+=aw,pos+=lowbit(pos);}int query(int pos){int res=0;while(pos)res+=tr[pos],pos-=lowbit(pos);return res;}
}pT[26],T;
class MulBitTree{private:int tr[MAXN],ip;public:void build(int id){ip=id;for(int i=1;i<=n;i++)tr[i]=1;}void insert(int pos,int aw){while(pos)tr[pos]=1ll*aw*tr[pos]%mo,pos-=lowbit(pos);}int query(int pos){int res=1;while(pos<=n)res=1ll*res*tr[pos]%mo,pos+=lowbit(pos);return res;}
}Bp[M];
void misakaAdd(int x,const int y,const int z){if(y==block[x])summ[y]=1ll*z*summ[y]%mo;else summ[y]=1ll*(z-1)*summ[y]%mo,Bp[y].insert(x,1ll*ff[z-1]*z%mo);
}
void misakaDel(int x,const int y,const int z){if(y==block[x])summ[y]=1ll*ff[z]*summ[y]%mo;else summ[y]=1ll*ff[z-1]*summ[y]%mo,Bp[y].insert(x,1ll*ff[z]*(z-1)%mo);
}
int sakura(int l,int r){int res=1;for(int j=l;j<=r;j++){int now=a[j];for(int k=head[j];k;k=nxt[k]){const int z=val[k],ip=tur[z];int num=0;while(now%z==0){now/=z;num++;if(vis[ip])res=1ll*z*res%mo;else res=1ll*(z-1)*res%mo,vis[ip]=1,sta[++stak]=ip;}}}return res;
}
int sakura2(int l,int r,const int al,const int ar){int res=1;for(int j=l;j<=r;j++){int now=a[j];for(int k=head[j];k;k=nxt[k]){const int z=val[k],ip=tur[z];int num=0;while(now%z==0){now/=z;num++;if(vis[ip]||cnt[ar][ip]>cnt[al][ip])res=1ll*z*res%mo;else res=1ll*(z-1)*res%mo,vis[ip]=1,sta[++stak]=ip;}}}return res;
}
signed main(){freopen("phi.in","r",stdin);freopen("phi.out","w",stdout);read(n);read(q);init();for(int i=1;i<=n;i++)read(a[i]);for(int i=1;i<=n;i++)block[i]=(i+n1-1)/n1;for(int i=1;i<=n;i++){if(!L[block[i]])L[block[i]]=i;R[block[i]]=i;}for(int i=1;i<=block[n];i++)Bp[i].build(i),summ[i]=1;for(int i=1;i<=n;i++){T.insert(i,a[i]);int now=a[i];work(i);for(int j=1;j<=10;j++){int tmp=0;while(now%prime[j]==0)now/=prime[j],tmp++;if(tmp)pT[j].insert(i,tmp);}const int ip=block[i];for(int j=head[i];j;j=nxt[j]){int num=0;const int x=val[j];while(now%x==0){s[x].insert(3*i+num);now/=x;it=s[x].lower_bound(3*i+num);num++;if(it!=s[x].begin()){it--;int vp=(*it)/3;misakaAdd(vp,ip,x);}else summ[ip]=1ll*(x-1)*summ[ip]%mo;}cnt[ip][tur[x]]+=num;}}for(int i=2;i<=block[n];i++)for(int j=11;j<=cntp;j++)cnt[i][j]+=cnt[i-1][j];for(int i=1;i<=q;i++){int opt,x,y;read(opt);read(x);read(y);if(opt==0){for(int j=1;j<=10;j++){int nowx=a[x],nowy=y,numx=0,numy=0; while(nowx%prime[j]==0)nowx/=prime[j],numx++;while(nowy%prime[j]==0)nowy/=prime[j],numy++;pT[j].insert(x,numy-numx);}int now=a[x];const int ip=block[x];for(int j=head[x];j;j=nxt[j]){int num=0;const int z=val[j];while(now%z==0){it=s[z].lower_bound(3*x+num);now/=z;int pp=0;if(it!=s[z].begin()){it--;int vp=(*it)/3;pp=vp;misakaDel(vp,ip,z);it++;}else summ[ip]=1ll*ff[z-1]*summ[ip]%mo;it++;if(it!=s[z].end()){int vp=(*it)/3;misakaDel(x,block[vp],z);if(pp)misakaAdd(pp,block[vp],z);else summ[block[vp]]=1ll*(z-1)*summ[block[vp]]%mo;}s[z].erase(3*x+num);num++;}for(int k=ip;k<=block[n];k++)cnt[k][tur[z]]-=num;}T.insert(x,y-a[x]);a[x]=y;work(x);now=y;for(int j=head[x];j;j=nxt[j]){int num=0;const int z=val[j];while(now%z==0){s[z].insert(3*x+num);it=s[z].lower_bound(3*x+num);num++;now/=z;int pp=0;if(it!=s[z].begin()){it--;int vp=(*it)/3;pp=vp;misakaAdd(vp,ip,z);it++;}else summ[ip]=1ll*(z-1)*summ[ip]%mo;it++;if(it!=s[z].end()){int vp=(*it)/3;if(pp)misakaDel(pp,block[vp],z);else summ[block[vp]]=1ll*ff[z-1]*summ[block[vp]]%mo;misakaAdd(x,block[vp],z);}}for(int k=ip;k<=block[n];k++)cnt[k][tur[z]]+=num;}}if(opt==1){int tmp=T.query(y)-T.query(x-1),res=1;for(int j=1;j<=cntp&&1ll*prime[j]*prime[j]<=tmp;j++){if(tmp%prime[j])continue;int num=0;while(tmp%prime[j]==0)tmp/=prime[j],num++;res=1ll*(prime[j]-1)*qkpow(prime[j],num-1,mo)%mo*res%mo;}if(tmp>1)res=1ll*(tmp-1)*res%mo;ans[++tott]=res;}if(opt==2){int res=1;for(int j=1;j<=10;j++){int tmp=pT[j].query(y)-pT[j].query(x-1);if(!tmp)continue;res=1ll*(prime[j]-1)*res%mo;res=1ll*res*qkpow(prime[j],tmp-1,mo)%mo;}if(block[x]==block[y]){res=1ll*res*sakura(x,y)%mo;ans[++tott]=res;while(stak)vis[sta[stak--]]=0;continue;}res=1ll*res*sakura(x,R[block[x]])%mo;for(int j=block[x]+1;j<block[y];j++)res=1ll*res*summ[j]%mo,res=1ll*res*Bp[j].query(x)%mo;res=1ll*res*sakura2(L[block[y]],y,block[x],block[y]-1)%mo;ans[++tott]=res;while(stak)vis[sta[stak--]]=0;}}while(tott)print(ans[tott--]);fwrite(opt,1,obuf+(1<<22)-opt,stdout);return 0;
}

谢谢!!!

[FJWC2018]欧拉函数相关推荐

  1. bzoj 5245: [Fjwc2018]欧拉函数 线段树+bitset

    题意 对于正整数 n,定义欧拉函数 φ(n) 为小于等于 n 且与 n 互质的正整数个数.例如 φ(1) = 1, φ(8) = 4. 给定正整数序列 a1, a2, · · · , an,请依次执行 ...

  2. poj2154-color-polyan次二面体+欧拉函数优化

    N<=1e9,O(nlogn)的做法会超时.从枚举置换转变为枚举轮换长度,然后可以利用欧拉函数,把复杂度变为O(√n * logn) 1 /*-------------------------- ...

  3. hdu 1286( 欧拉函数 )

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1286 数学题真的是有点吃不消了... View Code 1 #include<iostream ...

  4. 费马定理中值定理_数论-欧拉函数、欧拉定理

    欧拉函数 积性函数 满足 ( 互质) 定义 对于正整数 ,欧拉函数是小于等于 的所有数中与 互质的数的 个数. 欧拉函数是积性函数(这个证明不是很显然,这个链接里面有很多种证明方法) 记作: 公式 , ...

  5. poj2154(Polya+欧拉函数优化模版)

    #include <cstdio> #include <cstring> #include<iostream> using namespace std; const ...

  6. 【数学专题】约数个数与欧拉函数

    整理的算法模板合集: ACM模板 目录 一.约数个数 1. AcWing 1291. 轻拍牛头 2. AcWing 1294. 樱花 2.1 AcWing 197. 阶乘分解 3. AcWing 19 ...

  7. 【数学知识】三种方法求 [1,n] 中所有数欧拉函数(线性筛欧拉函数优化至 O(n) )

    整理的算法模板合集: ACM模板 ①直接求小于或等于n,且与n互质的数个数(求[1,n]中所有数的欧拉函数时间复杂度:O(nn)O(n\sqrt{n})O(nn​)) ②求[1,n]之间每个数的质因数 ...

  8. bzoj 1409 Password 矩阵快速幂+欧拉函数

    可以发现,该数组的mi就是斐波那契数列 所以要矩阵快速幂搞出第n位 但是斐波那契数列上涨的很快,这就需要欧拉定理了 p^phi(q)%q=1(gcd(p,q)==1) p是素数,所以可以用 然后需要5 ...

  9. hdu1695(莫比乌斯)或欧拉函数+容斥

    题意:求1-b和1-d之内各选一个数组成数对.问最大公约数为k的数对有多少个,数对是有序的.(b,d,k<=100000) 解法1: 这个能够简化成1-b/k 和1-d/k 的互质有序数对的个数 ...

  10. POJ 2480 (约数+欧拉函数)

    题目链接: http://poj.org/problem?id=2480 题目大意:求Σgcd(i,n). 解题思路: 如果i与n互质,gcd(i,n)=1,且总和=欧拉函数phi(n). 如果i与n ...

最新文章

  1. 转载~vim配置文件
  2. Pycharm基本操作
  3. 用博奥如何导入单项工程电子表_用博奥如何导入单项工程电子表_博奥常见问题处理汇总...
  4. leetcode第一题两数相加
  5. 依赖注入的三种方式_Java核心知识 Spring原理十 Spring 依赖注入四种方式
  6. Max Script|加密写法
  7. UG软件使用10大技巧,将会大大提升工作效率
  8. 如何在Win10安装“Siemens TIA Openness”
  9. 数学基础知识总结 —— 1. 常用导数公式
  10. 微信分享appID注册一次后即绑定该应用?
  11. NCA(Neighborhood Components Analysis)
  12. 服务器宝塔Error: connect ETIMEDOUT
  13. 使用JSON-Schema验证数据,第1部分
  14. Dynamo 论文解读
  15. Ubuntu上安装tinyproxy搭建HTTP代理服务器
  16. PwC 普华永道面试归来
  17. leetcode Ch3-DFS Backtracking II
  18. |sex[]_sum[],G_ans|L2-028 秀恩爱分得快
  19. SpringCloud搭建
  20. MySQL索引失效原因,SQL查询语句不走索引原因

热门文章

  1. CNN图像识别_算法篇
  2. endnotex8使用教程_EndNote X8使用教程
  3. 服务器数码管不显示,LED数码管不亮的原因及故障排查方法
  4. html当当图书榜页面,2019书排行榜_当当网图书排行榜
  5. wpf制作的画图软件
  6. EEGLAB的下载与安装
  7. EEGLAB教程-1.2通道定位
  8. oracle四大索引类型,oracle 索引类型
  9. matlab仿真元件,matlab电力系统仿真元件[高等教育]
  10. 杨辉三角 java版