【TJOI 2018】数学计算

【题目】

传送门

题目描述:

小豆现在有一个数 x x x,初始值为 1 1 1。小豆有 Q Q Q 次操作,操作有两种类型:

1 1 1 m m m x = x × m x=x\times m x=x×m 输出 x % m o d x\%mod x%mod

2 2 2 p o s pos pos x = x / x=x/ x=x/ p o s pos pos 次操作所乘的数(保证第 p o s pos pos 次操作一定为类型 1 1 1,对于每一个类型 1 1 1 的操作至多会被除一次)输出 x % m o d x\%mod x%mod

输入格式:

一共有 t t t 组输入 ( t ≤ 5 ) (t\leq5) (t5)

对于每一组输入,第一 行是两个数字 Q , m o d ( Q ≤ 100000 , m o d ≤ 100000000 ) Q,mod(Q\leq100000,mod\leq100000000) Q,mod(Q100000,mod100000000)

接下来 Q Q Q 行,每一行为操作类型 o p op op,操作编号或所乘的数字 m m m(保证所有的输入都是合法的)。

输出格式:

对于每一个操作,输出一行,包含操作执行后的 x % m o d x\%mod x%mod 的值

样例数据:

输入
1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7

输出
2
1
2
20
10
1
6
42
504
84

说明:

对于 20 % 20\% 20% 的数据, 1 ≤ Q ≤ 500 1\leq Q\leq 500 1Q500
对于 100 % 100\% 100% 的数据, 1 ≤ Q ≤ 100000 1\leq Q\leq100000 1Q100000


【分析】

其实这道题一开始想用模拟,但是由于模数不一定和被除数互质,所以不能快速求逆元,也就不能模拟了

这道题的正解是线段树,记录一下区间的乘积,那么每次 1 1 1 操作就在 i i i 位置乘 m m m 2 2 2 操作就把 p o s pos pos 位置的数变为 1 1 1

由于是单点修改,连懒标记都不用写

最后询问输出根节点的乘积就可以了


【代码】

#include<bits/stdc++.h>
#define N 100005
using namespace std;
int n,P,prod[N<<2];
#define mid ((l+r)>>1)
void build(int root,int l,int r){
	prod[root]=1;
	if(l==r)  return;
	build(root<<1,l,mid);
	build(root<<1|1,mid+1,r);
}
void Modify(int root,int l,int r,int x,int val){
	if(l==r)  {prod[root]=val;return;}
	if(x<=mid)  Modify(root<<1,l,mid,x,val);
	else  Modify(root<<1|1,mid+1,r,x,val);
	prod[root]=1ll*prod[root<<1]*prod[root<<1|1]%P;
}
#undef mid
int main(){
	int T;
	scanf("%d",&T);
	while(T--){
		int op,x;
		scanf("%d%d",&n,&P),build(1,1,n);
		for(int i=1;i<=n;++i){
			scanf("%d%d",&op,&x);
			if(op==1)  Modify(1,1,n,i,x),printf("%d\n",prod[1]);
			else  Modify(1,1,n,x,1),printf("%d\n",prod[1]);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值