正题
题目链接:https://www.luogu.com.cn/problem/CF1114F
题目大意
nnn个数的一个序列要求支持
- 区间乘上一个数
- 询问一个区间的乘积的φ\varphiφ值
解题思路
因为数很小,而我们求φ\varphiφ需要知道一个数所包含的质因子。发现在300300300以内的只有626262个质数,那么我们可以状态压缩起来一个数SSS表示状压后的所拥有的质数集合。
用线段树维护区间乘机和质数集合即可,时间复杂度O(nk+qlogn)O(nk+q\log n)O(nk+qlogn)
codecodecode
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll pri[62]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97,101,103,107,109,113,127,131,137,139,149,151,157,163,167,173,179,181,191,193,197,199,211,223,227,229,233,239,241,251,257,263,269,271,277,281,283,293};
const ll N=4e5+10,XJQ=1e9+7;
ll n,q,a[N],ans1,ans2;
ll w[N*4],v[N*4],lazyw[N*4],lazyv[N*4];
ll power(ll x,ll b){ll ans=1;while(b){if(b&1)ans=ans*x%XJQ;x=x*x%XJQ;b>>=1;}return ans;
}
ll check(ll x){ll ans=0;for(ll i=0;i<62;i++)if(x%pri[i]==0)ans|=(1ll<<i);return ans;
}
void Build(ll x,ll L,ll R){lazyw[x]=1;if(L==R){w[x]=a[L];v[x]=check(a[L]);return;}ll mid=(L+R)>>1;Build(x*2,L,mid);Build(x*2+1,mid+1,R);w[x]=w[x*2]*w[x*2+1]%XJQ;v[x]=v[x*2]|v[x*2+1];return;
}
void Downdata(ll x,ll l,ll mid,ll r){if(!lazyv[x])return;ll val=lazyw[x];w[x*2]=w[x*2]*power(val,mid-l+1)%XJQ;w[x*2+1]=w[x*2+1]*power(val,r-mid)%XJQ;lazyw[x*2]=lazyw[x*2]*val%XJQ;lazyw[x*2+1]=lazyw[x*2+1]*val%XJQ;v[x*2]|=lazyv[x];v[x*2+1]|=lazyv[x];lazyv[x*2]|=lazyv[x];lazyv[x*2+1]|=lazyv[x];lazyw[x]=1;lazyv[x]=0;return;
}
void Change(ll x,ll L,ll R,ll l,ll r,ll val){if(L==l&&R==r){ll k=check(val);v[x]|=k;w[x]=w[x]*power(val,R-L+1)%XJQ;lazyw[x]=lazyw[x]*val%XJQ;lazyv[x]|=k;return;}ll mid=(L+R)>>1;Downdata(x,L,mid,R);if(r<=mid)Change(x*2,L,mid,l,r,val);else if(l>mid)Change(x*2+1,mid+1,R,l,r,val);else Change(x*2,L,mid,l,mid,val),Change(x*2+1,mid+1,R,mid+1,r,val);w[x]=w[x*2]*w[x*2+1]%XJQ;v[x]=v[x*2]|v[x*2+1];return;
}
void Ask(ll x,ll L,ll R,ll l,ll r){if(L==l&&R==r){ans1=ans1*w[x]%XJQ;ans2=ans2|v[x];return;}ll mid=(L+R)>>1;Downdata(x,L,mid,R);if(r<=mid)Ask(x*2,L,mid,l,r);else if(l>mid)Ask(x*2+1,mid+1,R,l,r);else Ask(x*2,L,mid,l,mid),Ask(x*2+1,mid+1,R,mid+1,r);return;
}
int main()
{scanf("%lld%lld",&n,&q);for(ll i=1;i<=n;i++)scanf("%lld",&a[i]);Build(1,1,n);while(q--){char op[10];ll l,r,x;scanf("%s%lld%lld",op,&l,&r);if(op[0]=='M'){scanf("%lld",&x);Change(1,1,n,l,r,x);}else{ans1=1;ans2=0;Ask(1,1,n,l,r);for(ll i=0;i<62;i++)if((ans2>>i)&1)ans1=ans1*(pri[i]-1)%XJQ*power(pri[i],XJQ-2)%XJQ;printf("%lld\n",ans1);}}
}