P4588
[TJOI2018]数学计算
本质是线段树。。。
问题是为什么不能求逆元。其实费马小定理求逆元必须满足模数是质数,而乘法逆元存在的条件是该数与模数互质。显然这题一个条件也不满足。。。
所以其实这题就是强迫做一个暴力优化,显然线段树是一个不错的选择。
线段树的写法相当暴力,将每次操作视为单点修改,每次输出视为求区间乘积。
时间复杂度
代码:
#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const ll N=1e5;
struct segment_tree{
ll l,r,mul;
#define l(x) tree[x].l
#define r(x) tree[x].r
#define mul(x) tree[x].mul
}tree[N*4+5];
ll T,q,mo,type,x;
void build(ll p,ll l,ll r) {
l(p)=l;r(p)=r;
if(l==r) {mul(p)=1;return;}
ll mid=(l+r)>>1;
build(p*2,l,mid);build(p*2+1,mid+1,r);
mul(p)=(mul(p*2)*mul(p*2+1))%mo;
}
void change(ll p,ll pos,ll x) {
if(l(p)==r(p)) {mul(p)=x;return;}
ll mid=(l(p)+r(p))>>1;
if(pos<=mid) change(p*2,pos,x);
if(pos>mid) change(p*2+1,pos,x);
mul(p)=(mul(p*2)*mul(p*2+1))%mo;
}
ll getmul(ll p,ll l,ll r) {
if(l<=l(p)&&r>=r(p)) return mul(p);
ll mid=(l(p)+r(p))>>1;
ll res=1;
if(l<=mid) res=(res*getmul(p*2,l,r))%mo;
if(r>mid) res=(res*getmul(p*2+1,l,r))%mo;
return res%mo;
}
inline ll read() {
ll ret=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') f=-f;ch=getchar();}
while(ch>='0'&&ch<='9') {ret=(ret<<3)+(ret<<1)+ch-'0';ch=getchar();}
return ret*f;
}
void write(ll x) {
if(x<0) {x=-x;putchar('-');}
ll y=10,len=1;
while(y<=x) {y*=10;len++;}
while(len--) {y/=10;putchar(x/y+48);x%=y;}
}
int main() {
T=read();
while(T--) {
q=read();mo=read();
build(1,1,q);
for(ll i=1;i<=q;i++) {
type=read();x=read();
if(type==1) {
change(1,i,x);
write(getmul(1,1,i)%mo);putchar('\n');
}
if(type==2) {
change(1,x,1);
write(getmul(1,1,i)%mo);putchar('\n');
}
}
}
return 0;
}