大致题意:给你一长度为n的序列,和q个操作。一个是区间乘以某个数字,另一个是查询区间积的欧拉函数对1e9+7取模的结果。出了n和q,这里所有出现的数字都是小于300的。
这里如果直接做,显然是不行的,因为欧拉函数虽然具有积性,但是并不能够取模,意味着不能直接保存区间积。同时,欧拉函数不具有完全积性,当gcd不为1的时候,不是直接相乘。但是这里有一个很重要的条件,即出现的每个数字都是小于300的,而300以内的质数恰好有62个,而2^62恰好可以用long long存下,这也就暗示了我们可以用状态压缩的方式,存储每个质数是否作为质因子出现。
根据欧拉函数的性质φ(p^x)=(p-1)p^(x-1),为了方便,我们不妨令φ'(p^x)=p^x,然后在线段树中每次计算区间的φ'和用LL状压表示点区间积的质因子。在合并的时候,状态直接用按位或,而φ'则是直接相乘取模即可。对于每一个询问,我们在线段树中求出φ',然后再通过乘以每一个质因子的逆元和质因子减一,把φ'变成φ之后输出。具体见代码:
#include <bits/stdc++.h>
#define INF 1e18
#define fi first
#define se second
#define LL long long
#define sc(x) scanf("%d",&x)
#define scc(x,y) scanf("%d%d",&x,&y)
#define sccc(x,y,z) scanf("%d%d%d",&x,&y,&z)
using namespace std;
const int N = 400010;
const int mod = 1e9 + 7;
int b[N],p[N],phi[N],inv[N],n,q,sz;
bool isp[N]; char s[100];
LL a[N],pw[N];
pair<LL,LL> c=make_pair(0LL,1LL);
inline LL qpow(LL x,LL n)
{
LL res=1;
while(n)
{
if (n&1) res=res*x%mod;
x=x*x%mod; n>>=1;
}
return res;
}
struct ST
{
#define ls i<<1
#define rs i<<1|1
struct node
{
pair<LL,LL> phi,lazy;
int l,r;
} T[N<<2];
inline void push_up(int i)
{
T[i].phi.fi=T[ls].phi.fi|T[rs].phi.fi;
T[i].phi.se=T[ls].phi.se*T[rs].phi.se%mod;
}
inline void upd(pair<LL,LL> &a,pair<LL,LL> b)
{
a.fi|=b.fi;
a.se=a.se*b.se%mod;
}
void build(int i,int l,int r)
{
T[i]=node{c,c,l,r};
if (l==r)
{
T[i].phi=make_pair(a[l],b[l]);
return;
}
int mid=(l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
push_up(i);
}
inline void push_down(int i)
{
pair<LL,LL> tmp=T[i].lazy;
upd(T[ls].lazy,T[i].lazy);
upd(T[rs].lazy,T[i].lazy);
int sz=T[ls].r-T[ls].l+1;
tmp.se=qpow(T[i].lazy.se,sz);
upd(T[ls].phi,tmp);
sz=T[rs].r-T[rs].l+1;
tmp.se=qpow(T[i].lazy.se,sz);
upd(T[rs].phi,tmp);
T[i].lazy=c;
}
void update(int i,int l,int r,pair<LL,LL> x)
{
if (T[i].l==l&&T[i].r==r)
{
upd(T[i].lazy,x);
x.se=qpow(x.se,r-l+1);
upd(T[i].phi,x); return;
}
if (T[i].lazy!=c) push_down(i);
int mid=(T[i].l+T[i].r)>>1;
if (mid>=r) update(ls,l,r,x);
else if (mid<l) update(rs,l,r,x);
else
{
update(ls,l,mid,x);
update(rs,mid+1,r,x);
}
push_up(i);
}
pair<LL,LL> getphi(int i,int l,int r)
{
if (T[i].l==l&&T[i].r==r) return T[i].phi;
if (T[i].lazy!=c) push_down(i);
int mid=(T[i].l+T[i].r)>>1;
if (mid>=r) return getphi(ls,l,r);
else if (mid<l) return getphi(rs,l,r);
else
{
pair<LL,LL> a,b;
a=getphi(ls,l,mid);
b=getphi(rs,mid+1,r);
upd(a,b); return a;
}
}
} seg;
void init()
{
sz=0; phi[1]=1;
for(int i=0;i<62;i++)
pw[i]=1LL<<i;
for(int i=2;i<301;i++)
{
if(!isp[i])p[++sz]=i,phi[i]=i-1;
for(int j=1;j<=sz&&(LL)i*p[j]<N;j++)
{
isp[i*p[j]]=1;
if(i%p[j]==0)
{
phi[p[j]*i]=phi[i]*p[j];
break;
} else phi[p[j]*i]=(p[j]-1)*phi[i];
}
}
inv[0]=inv[1]=1;
for(int i=2;i<301;i++)
inv[i]=(mod-mod/i)*(LL)inv[mod%i]%mod;
}
int main()
{
init(); scc(n,q);
for(int i=1;i<=n;i++)
{
int x,xx; sc(x); xx=x;
for(int j=1;j<=sz&&p[j]<=x;j++)
while (x%p[j]==0) x/=p[j],a[i]|=pw[j-1];
b[i]=xx;
}
seg.build(1,1,n);
while(q--)
{
scanf("%s",s);
if (s[0]=='T')
{
int x,y; scc(x,y);
pair<LL,LL> tmp=seg.getphi(1,x,y);
LL res=tmp.se;
for(int i=1;i<=62;i++)
if (tmp.fi&(1LL<<(i-1))) res=res*inv[p[i]]%mod*(p[i]-1)%mod;
printf("%lld\n",res);
} else
{
LL tmp=0;
int x,y,z,zz; sccc(x,y,z); zz=z;
for(int i=1;i<=sz&&p[i]<=z;i++)
while (z%p[i]==0) z/=p[i],tmp|=pw[i-1];
seg.update(1,x,y,make_pair(tmp,zz));
}
}
return 0;
}