题面:
CodeForces - 1114F: Please, another Queries on Array?
题意:
给定一个数组,Q次操作,(1)【L,R】区间乘X,(2)询问区间乘积的欧拉函数
分析:
X和原数组的值都小于等于300,而300以内的质数只有62个,似乎可以在线段树上每个节点开一个大小为62的数组保存当前区间每个质数的出现次数,快速幂求欧拉函数就好了,N又大了点,要开将近1e8的数组,肯定是被卡了的;注意到 phi(x) = x * (p1-1)/p1 * (p2-1)/p2 * ... *(pn-1)/pn,所以只需要保存区间中所有数的乘积和每个质数出现的情况即可,62个素数刚好状压一下
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1e9+7;
const int maxn = 4e5+45;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -1;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
return x * f;
}
inline void write(int x)
{
if(x<0) putchar('-'),x=-x;
if(x>9) write(x/10);
putchar(x%10+'0');
}
int n,q,l,r,x,a[maxn],id[320],val[320];
char op[20];
LL sz[maxn<<2],sb[maxn<<2],lz[maxn<<2],lb[maxn<<2],bit[320],inv[320];
/*
sz[]保存区间乘积 sb[]区间乘积包含的素数
lz[]懒惰标记区间乘 lb[]懒惰标记包含的素数
bit[]每个数包含素数的状压
inv[]预处理逆元
*/
void init()
{
int cnt = 0;
for(int i = 2; i <= 300; ++i){
bool flag = true;
for(int j = 2; j*j <= i; ++j){
if(i % j == 0) flag = false;
}
if(flag) id[i] = cnt++,val[cnt-1] = i;
}
for(int i = 2;i <= 300; ++i){
int x = i;
for(int j = 2;j*j<=x; ++j){
if(x % j == 0){
bit[i] |= (1ll<<id[j]);
while(x % j == 0) x /= j;
}
}
if(x > 1) bit[i] |= (1ll<<id[x]);
}
inv[1] = 1; //预处理逆元
for(int i = 2;i <= 300; ++i) inv[i] = (mod-mod/i)*inv[mod%i]%mod;
}
inline LL qpow(LL a,LL x)
{
LL res = 1ll; a %= mod;
while(x){
if(x&1) res = res * a % mod;
a = a * a % mod;
x >>= 1;
}
return res;
}
inline void pushup(int x){
sz[x] = sz[x<<1]*sz[x<<1|1]%mod;
sb[x] = sb[x<<1]|sb[x<<1|1];
}
inline void pushdown(int x,int l,int r){
int mid = (l+r)>>1;
sz[x<<1] = sz[x<<1]*qpow(lz[x],mid-l+1)%mod;
sb[x<<1] |= lb[x];
sz[x<<1|1] = sz[x<<1|1]*qpow(lz[x],r-mid)%mod;
sb[x<<1|1] |= lb[x];
lz[x<<1] = lz[x<<1]*lz[x]%mod;
lb[x<<1] |= lb[x];
lz[x<<1|1] = lz[x<<1|1]*lz[x]%mod;
lb[x<<1|1] |= lb[x];
lz[x] = 1; lb[x] = 0;
}
void build(int l,int r,int x)
{
lz[x] = 1;
if(l == r){
sz[x] = a[l];
sb[x] = bit[a[l]];
return ;
}
int mid = (l+r) >> 1;
build(l,mid,x<<1);
build(mid+1,r,x<<1|1);
pushup(x);
}
void updata(int l,int r,int L,int R,int x,int v)
{
if(l > R || r < L) return ;
if(l >= L && r <= R){
sz[x] = sz[x] * qpow(v,r-l+1) % mod;
sb[x] |= bit[v];
lz[x] = lz[x] * v % mod;
lb[x] |= bit[v];
return ;
}
if(lb[x]) pushdown(x,l,r);
int mid = (l+r) >> 1;
updata(l,mid,L,R,x<<1,v);
updata(mid+1,r,L,R,x<<1|1,v);
pushup(x);
}
void query(int l,int r,int L,int R,int x,LL &res,LL &t)
{
if(l > R || r < L) return ;
if(l >= L && r <= R){
res = res * sz[x] % mod;
t |= sb[x];
return ;
}
if(lb[x]) pushdown(x,l,r);
int mid = (l+r) >> 1;
query(l,mid,L,R,x<<1,res,t);
query(mid+1,r,L,R,x<<1|1,res,t);
}
int main()
{
n = read(), q = read();
for(int i = 1; i <= n; ++i) a[i] = read();
init(); build(1,n,1);
while(q--)
{
scanf("%s",op);
if(op[0] == 'M'){
l = read(),r = read(),x = read();
updata(1,n,l,r,1,x);
}
else
{
l = read(),r = read();
LL res = 1,t = 0,p = 1;
query(1,n,l,r,1,res,t);
for(int i = 62; ~i; --i){
if(t&(1ll<<i)) p = p*(val[i]-1)%mod*inv[val[i]]%mod;
}
write(res*p%mod); putchar('\n');
}
}
return 0;
}