题目:luogu4588.
题目大意:
对于一个数x,需要支持两种操作:
1.格式1 m,使得x=x*m,并输出x%mod的值.
2.格式2 pos,使得x=x/第pos操作的m,并输出x%mod的值.
不得不说这道题的思路确实比较好,但是想到也不是太难.
一开始我看到要对一个数取模还有除法,我第一个想到的方法就是直接特别暴力地使用逆元,然后直接做.
可是这道题由于模数不保证是质数,这代表我们不能O(log(n))处理逆元,然而我们要使用O(sqrt(n))的欧拉定理求逆元会TLE,所以我们这道题其实并不能以一种数学角度去做.
现在我们重新换一种方式做,现在我们维护一个序列便是每次操作1后会对乘积产生的贡献,特别的,对于操作2,我们只记录一个数值1.
现在,对于每一次操作2,我们都将位置pos的数值修改成1,并输出一个前缀积.
这样这道题就完美解决了.
代码如下:
#include<bits/stdc++.h>
using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=100000;
const int INF=(1<<30)-1+(1<<30);
struct tree{
int l,r;
LL mul;
}tr[N*5];
int q;
LL mod;
void build(int L,int R,int k=1){
tr[k].l=L;tr[k].r=R;
if (L==R) return;
int mid=L+R>>1;
build(L,mid,k<<1),build(mid+1,R,k<<1|1);
}
void change(int x,LL num,int k=1){
if (tr[k].l==tr[k].r){
tr[k].mul=num%mod;
return;
}
int mid=tr[k].l+tr[k].r>>1;
if (x<=mid) change(x,num,k<<1);
else change(x,num,k<<1|1);
tr[k].mul=tr[k<<1].mul*tr[k<<1|1].mul%mod;
}
LL query(int L,int R,int k=1){
if (L==tr[k].l&&R==tr[k].r) return tr[k].mul;
int mid=tr[k].l+tr[k].r>>1;
if (R<=mid) return query(L,R,k<<1);
else if (L>mid) return query(L,R,k<<1|1);
else return query(L,mid,k<<1)*query(mid+1,R,k<<1|1)%mod;
}
Abigail into(){
for (int i=0;i<N*5;i++)
tr[i].l=tr[i].r=0,tr[i].mul=1;
scanf("%d%lld",&q,&mod);
}
Abigail work(){
int opt,pos;
LL m;
build(1,q);
for (int i=1;i<=q;i++){
scanf("%d",&opt);
if (opt==1){
scanf("%lld",&m);
change(i,m);
printf("%lld\n",query(1,i));
}else{
scanf("%d",&pos);
change(pos,1);change(i,1);
printf("%lld\n",query(1,i));
}
}
}
Abigail outo(){
}
int main(){
int T;
scanf("%d",&T);
while (T--){
into();
work();
outo();
}
return 0;
}