P4588 [TJOI2018] 数学计算
题目描述
小豆现在有一个数 \(x\),初始值为 \(1\)。小豆有 \(Q\) 次操作,操作有两种类型:
1 m:将 \(x\) 变为 \(x \times m\),并输出 \(x \bmod M\)
2 pos:将 \(x\) 变为 \(x\) 除以第 \(pos\) 次操作所乘的数(保证第 \(pos\) 次操作一定为类型 1,对于每一个类型 1 的操作至多会被除一次),并输出 \(x \bmod M\)。
输入格式
一共有 \(t\) 组输入。
对于每一组输入,第一行是两个数字 \(Q,M\)。
接下来 \(Q\) 行,每一行为操作类型 \(op\),操作编号或所乘的数字 \(m\)(保证所有的输入都是合法的)。
输出格式
对于每一个操作,输出一行,包含操作执行后的 \(x \bmod M\) 的值。
输入输出样例 #1
输入 #1
1
10 1000000000
1 2
2 1
1 2
1 10
2 3
2 4
1 6
1 7
1 12
2 7
输出 #1
2
1
2
20
10
1
6
42
504
84
说明/提示
对于 \(20\%\) 的数据,\(1 \le Q \le 500\)。
对于 \(100\%\) 的数据,\(1 \le Q \le 10^5\),\(t \le 5,1 \lt M \le 10^9\),\(0 < m \leq 10^9\)。
题解
第一反应是直接模拟,直接把每次操作的数计算下来就好,然后操作二的时候直接除就好
然后发现你要除去的是真实的\(x\times m\),你输出的是 \(x\times m \mod M\) ,如果只是单纯的记录 \(x\times m\) ,毫无疑问会爆 long long
当然我们可以直接上python,但是感觉出题人一样会把我们卡死
那使用乘法逆元直接去做似乎可以,然后发现 \(M\) 是输入的,没有保证一定是质数,也没有保证 \(x\mod M \neq 0\) ,乘法逆元也被出题人防死了
发现把每次操作看做一个位置,整个操作1的序列就是一个区间,当前操作就是要你维护类似整个区间的前缀积,然后我们就想到可以用类似线段树的方法维护
其实我开始根本看不出这和线段树有半根毛的关系
对于操作1 m, 将当前最尾部的操作位置的值设置为\(m\),然后线段树上更新前缀积
对于操作2 pos,将操作序列第pos 位置的值改成1(这和除法操作等价),然后线段树上更新维护前缀积
这样子我们通过维护前缀积,避免了记录除法/乘法逆元的操作,这样在取模意义下也是合法的
代码
#include<bits/stdc++.h>
// #define mod 998244353
// #define int long long //由于作者比较懒,所以直接使用这个了
using namespace std;
typedef long long ll;
typedef __int128 ix;
typedef long double ldb;
const ll V = 2e5 + 100;
const int INF = 1e9 + 7;
void solve()
{int q,mod;cin >> q >> mod;vector<ll> mul(4 * q + 1);auto update = [&](int x) ->void{mul[x] = mul[2 * x] * mul[2 * x + 1] % mod;};auto build = [&](auto&& self,int now,int l,int r) ->void{if(l == r){mul[now] = 1;return ;}int mid = (l + r) >> 1;self(self,2 * now,l,mid);self(self,2 * now + 1,mid + 1,r);update(now);};auto modify = [&](auto&&self,int now,int l,int r,int x,int y,ll val) ->void{if(x <= l && r <= y){mul[now] = val % mod;return ;}int mid = (l + r) >> 1;if(x <= mid) self(self,2 * now,l,mid,x,y,val);if(mid + 1 <= y) self(self,2 * now + 1,mid + 1,r,x,y,val);update(now);};build(build,1,1,q);for(int i = 1;i <= q;++i){int opt,m;cin >> opt >> m;if(opt == 1) modify(modify,1,1,q,i,i,(ll)m);else modify(modify,1,1,q,m,m,1ll);ll ans = mul[1] % mod;cout << ans << "\n";}
}
signed main()
{std::ios::sync_with_stdio(false);std::cin.tie(nullptr);std::cout.tie(nullptr);int t;cin >> t;while(t--) solve();return 0;
}