https://codeforces.com/contest/1114/problem/F
欧拉函数 + 区间更新线段树
题意
对一个序列(n<=4e5,a[i]<=300)两种操作:
1. 将a[l,r]的数字乘以x(x<=300)
2. 求\(\varphi(\prod_{i=l}^ra[i])\)对1e9+7取模
题解
欧拉函数性质
- 假如\(p\)是一个质数,\(\varphi(p)=p-1\),\(\varphi(p^k)=p^{k-1}*(p-1)=p^k*\frac{p-1}{p}\)
- 假如p,q互质,\(\varphi(p*q)=\varphi(p)*\varphi(q)\)
- 对于一个正整数n,\(\varphi(n)=n*\frac{p_1-1}{p_1}*...*\frac{p_n-1}{p_n}\)
-
对于每个数分开维护\(n\)和\(\frac{p_1-1}{p_1}*...*\frac{p_n-1}{p_n}\),因为所有数只有300大,有62位素数,所以可以用位运算维护后半部分,剩下前半部分就是维护数的乘积
处理
- 开两个标记数组,ly[]维护乘积的延迟标记,st[]维护位运算的延迟标记
- 每次区间操作找到合适的区间就直接修改,需要向下递归前才向下推标记
- 预处理出x(x<=300)每个数的素因子bit[],可以在埃式筛的过程中处理
- 查询的时候,需要用两个信息用array<ll,2>,
附上重载加号代码
array<ll,2> operator +(array<ll,2> a,array<ll,2> b){ return {a[0]*b[0]%P,a[1]|b[1]}; }
代码(区间修改线段树板子)
#include<bits/stdc++.h> #define P 1000000007 #define ls (o<<1) #define rs (o<<1|1) #define ll long long #define M 1600000 using namespace std; ll x[M],s[M],ly[M],st[M]; ll bit[305],pr[305],inv[305]; int vi[305]; ll a[400005],tp,X,cnt,i; int n,q,l,r; char S[20]; array<ll,2>ans; array<ll,a[1]|b[1]}; } ll pw(ll bs,ll x){ ll ans=1;while(x){if(x&1)ans=ans*bs%P;bs=bs*bs%P;x>>=1;} return ans; } void push_up(int o){ //st数组和ly数组同理,作用为标记每次改变量 x[o]=x[ls]*x[rs]%P; s[o]=s[ls]|s[rs]; ly[o]=1; st[o]=0; } void push_down(int o,int l,int r){ //更新子节点信息,将本节点标记去掉 int mid=(l+r)/2; if(ly[o]>1){ ly[ls]=ly[ls]*ly[o]%P; ly[rs]=ly[rs]*ly[o]%P; s[ls]=s[ls]|st[o]; st[ls]=st[ls]|st[o]; s[rs]=s[rs]|st[o]; st[rs]=st[rs]|st[o]; x[ls]=x[ls]*pw(ly[o],mid-l+1)%P; x[rs]=x[rs]*pw(ly[o],r-mid)%P; ly[o]=1; st[o]=0; } } void build(int o,int r){ if(l==r){ ly[o]=x[o]=a[l]; st[o]=s[o]=bit[a[l]]; return; } int mid=(l+r)/2; build(ls,mid);build(rs,mid+1,r); push_up(o); } array<ll,2> qy(int o,int r,int L,int R){ int mid=(l+r)/2; array<ll,2>ans={1,0}; if(L<=l&&r<=R){ return {x[o],s[o]}; } push_down(o,r); if(L<=mid)ans=ans+qy(ls,mid,L,R); if(R>mid)ans=ans+qy(rs,r,R); return ans; } void ud(int o,int R,ll X){ int mid=(l+r)/2; //if(l!=r)push_down(o,r); //1.先要将上次的信息传下去不然就会清空了2.并且要特判是不是最后一层 if(L<=l&&r<=R){ ly[o]=X*ly[o]%P;x[o]=x[o]*pw(X,r-l+1)%P; st[o]|=bit[X];s[o]|=bit[X]; return; } push_down(o,r); //只要不向下搜就不向下推 if(L<=mid)ud(ls,R,X); if(R>mid)ud(rs,X); push_up(o); //更新了才需要向上推 } void init(){ for(int i=2;i<301;i++){ if(!vi[i]){ pr[++cnt]=i; inv[cnt]=pw(i,P-2); for(int j=i;j<301;j+=i){ vi[j]=1;bit[j]|=(1ll<<cnt); } } } } int main(){ init(); cin>>n>>q; for(i=1;i<=n;i++)scanf("%lld",&a[i]); build(1,1,n); while(q--){ scanf("%s",S); if(S[0]=='M'){ scanf("%d%d%lld",&l,&r,&X); ud(1,n,X); }else{ scanf("%d%d",&r); ans=qy(1,r); tp=ans[0]%P; for(i=1;i<63;i++){ if((ans[1]>>i)&1)tp=tp*(pr[i]-1)%P*inv[i]%P; } printf("%lld\n",tp); } } }
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。