CF1114F Please, another Queries on Array?
思路
由发现,对于区间的询问,只需要维护出区间乘积,该乘积的质因数有哪些,就可以算出答案。区间乘积很好维护。
考虑如何求这个乘积包含的质因数,题目中,而以内的质数只有个,所以可以采取类似状态压缩的思想,用一个类型的数字记录某个区间的乘积包含了哪些质因数,合并两个区间时直接把这两个状态按位或起来即可。带修改操作,所以放到线段树上做。
代码
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
const ll N=4E5+10,P=1E9+7;
ll n,q;
ll he[N],one[N],a[N],t[4*N],tag[4*N],otag[4*N],sta[4*N],f[100];
vector<ll> pri;
struct Node
{
ll val,state;
};
ll ksm(ll x,ll y)
{
ll ret=1;
x%=P;
while(y)
{
if(y&1)
ret=ret*x%P;
x=x*x%P;
y>>=1;
}
return ret;
}
void sieve()
{
rep(i,2,300)
{
if(!he[i])
{
he[i]=1;
pri.emplace_back(i);
}
for(auto k:pri)
{
if(k*i>300)
break;
he[i*k]=1;
if(i%k==0)
break;
}
}
}
ll find(ll x)
{
ll ret=0;
rep(i,0,pri.size()-1)
{
ll k=pri[i];
if(x%k==0)
{
ret|=1ll<<i;
while(x%k==0)
x/=k;
}
}
return ret;
}
void update(ll p)
{
t[p]=t[lc]*t[rc]%P;
sta[p]=sta[lc]|sta[rc];
}
void build(ll p,ll l,ll r)
{
tag[p]=1;
if(l==r)
{
sta[p]=one[a[l]];
t[p]=a[l];
return;
}
ll mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
update(p);
}
void flag(ll p,ll len,ll val,ll o)
{
t[p]=t[p]*ksm(val,len)%P;
tag[p]=tag[p]*val%P;
sta[p]|=o;
otag[p]|=o;
}
void push_down(ll p,ll l,ll r)
{
ll mid=(l+r)>>1;
flag(lc,mid-l+1,tag[p],otag[p]);
flag(rc,r-mid,tag[p],otag[p]);
tag[p]=1;
otag[p]=0;
}
void modify(ll p,ll l,ll r,ll al,ll ar,ll val)
{
if(al<=l && ar>=r)
{
flag(p,r-l+1,val,one[val]);
return;
}
ll mid=(l+r)>>1;
if(otag[p])
push_down(p,l,r);
if(al<=mid)
modify(lc,l,mid,al,ar,val);
if(ar>mid)
modify(rc,mid+1,r,al,ar,val);
update(p);
}
Node merge(Node u,Node v)
{
u.val=u.val*v.val%P;
u.state|=v.state;
return u;
}
Node query(ll p,ll l,ll r,ll al,ll ar)
{
if(al<=l && ar>=r)
return {t[p],sta[p]};
ll mid=(l+r)>>1;
if(otag[p])
push_down(p,l,r);
if(ar<=mid)
return query(lc,l,mid,al,ar);
if(al>mid)
return query(rc,mid+1,r,al,ar);
return merge(query(lc,l,mid,al,ar),query(rc,mid+1,r,al,ar));
}
void print()
{
rep(i,1,4*n)
{
op(i,t[i]);
en;
}
en;
}
int main()
{
sieve();
rep(i,0,61)
f[i]=(pri[i]-1)*ksm(pri[i],P-2)%P;
read(n,q);
rep(i,1,n)
read(a[i]);
rep(i,1,300)
one[i]=find(i);
build(1,1,n);
string ty;
ll l,r,x;
while(q--)
{
cin>>ty;
read(l,r);
if(ty[0]=='T')
{
Node res=query(1,1,n,l,r);
ll ans=res.val;
rep(i,0,61)
if((1ll<<i)&res.state)
ans=ans*f[i]%P;
OP(ans);
}
else
{
read(x);
modify(1,1,n,l,r,x);
}
}
}
思路
刚开始想每次给乘上数字,除法运算时乘逆元就行,但是并不一定是质数(当且仅当互质时,对模数存在逆元)。
设为第次操作时给乘的数字,初始时全为,那么所有的乘积就是当前的值(类似区间和),操作二就是将归为,容易想到用线段树维护一下,比较像上海市赛的签到题,但是那道题没有修改操作,只需要维护下前缀乘积即可。
代码
#include<bits/stdc++.h>
#define lc p<<1
#define rc p<<1|1
#define rep(i,st,ed) for(int i=st;i<=ed;++i)
#define bl(u,i) for(int i=head[u];i;i=e[i].nxt)
#define en puts("")
#define LLM LONG_LONG_MAX
#define LLm LONG_LONG_MIN
#define pii pair<ll,ll>
typedef long long ll;
typedef double db;
using namespace std;
const ll INF=0x3f3f3f3f;
void read() {}
void OP() {}
void op() {}
template <typename T, typename... T2>
inline void read(T &_, T2 &... oth)
{
int __=0;
_=0;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-')
__=1;
ch=getchar();
}
while(isdigit(ch))
{
_=_*10+ch-48;
ch=getchar();
}
_=__?-_:_;
read(oth...);
}
template <typename T>
void Out(T _)
{
if(_<0)
{
putchar('-');
_=-_;
}
if(_>=10)
Out(_/10);
putchar(_%10+'0');
}
template <typename T, typename... T2>
inline void OP(T _, T2... oth)
{
Out(_);
putchar('\n');
OP(oth...);
}
template <typename T, typename... T2>
inline void op(T _, T2... oth)
{
Out(_);
putchar(' ');
op(oth...);
}
/*#################################*/
const ll N=1E5+10;
ll n,P;
ll ans[4*N];
vector<ll> ve;
void update(ll p)
{
ans[p]=ans[lc]*ans[rc]%P;
}
void build(ll p,ll l,ll r)
{
if(l==r)
{
ans[p]=1;
return;
}
ll mid=(l+r)>>1;
build(lc,l,mid);
build(rc,mid+1,r);
update(p);
}
void modify(ll p,ll l,ll r,ll pos,ll val)
{
if(l==r)
{
ans[p]=val>0?val%P:1;
return;
}
ll mid=(l+r)>>1;
if(pos<=mid)
modify(lc,l,mid,pos,val);
else
modify(rc,mid+1,r,pos,val);
update(p);
}
void solve()
{
read(n,P);
build(1,1,n);
ll ty,x;
rep(i,1,n)
{
read(ty,x);
if(ty==1)
modify(1,1,n,i,x);
else
modify(1,1,n,x,-ve[x-1]);
ve.emplace_back(x);
OP(ans[1]);
}
}
int main()
{
int _;
cin>>_;
while(_--)
{
solve();
}
}