传送门: https://codeforces.com/contest/1493/problem/D
题意
给 一 个 长 度 为 n 的 序 列 , 有 q 个 操 作 , 每 次 操 作 会 将 第 i 个 数 乘 x , 在 输 出 g c d ( 所 有 数 ) . 给一个长度为n的序列,有q个操作,每次操作会将第i个数乘x,在输出gcd(所有数). 给一个长度为n的序列,有q个操作,每次操作会将第i个数乘x,在输出gcd(所有数).
思路
因
为
每
次
操
作
只
对
一
个
数
操
作
,
而
不
是
区
间
修
改
,
而
且
是
不
是
求
区
间
g
c
d
。
因为每次操作只对一个数操作,而不是区间修改,而且是不是求区间gcd。
因为每次操作只对一个数操作,而不是区间修改,而且是不是求区间gcd。
即
不
需
要
用
线
段
树
求
区
间
g
c
d
,
可
以
用
可
以
动
态
开
点
维
护
每
个
质
因
子
的
m
i
n
值
。
即不需要用线段树求区间gcd,可以用可以动态开点维护每个质因子的min值。
即不需要用线段树求区间gcd,可以用可以动态开点维护每个质因子的min值。
g c d = p 1 m i n ( k 1 , k 2 . . . k n ) . . . p n m i n ( k 1 , k 2 . . . k n ) gcd=p_1^{min(k_1,k_2...k_n)}...p_n^{min(k_1,k_2...k_n)} gcd=p1min(k1,k2...kn)...pnmin(k1,k2...kn)
本
篇
题
解
是
利
用
m
u
l
t
i
s
e
t
维
护
每
个
质
因
子
的
m
i
n
值
。
本篇题解是利用multiset维护每个质因子的min值。
本篇题解是利用multiset维护每个质因子的min值。
因
为
m
u
l
t
i
s
e
t
每
次
操
作
都
是
log
n
,
而
且
m
t
l
t
i
s
e
t
内
部
都
是
有
序
的
,
可
重
复
的
,
简
直
完
美
!
因为multiset每次操作都是\log n,而且mtltiset内部都是有序的,可重复的,简直完美!
因为multiset每次操作都是logn,而且mtltiset内部都是有序的,可重复的,简直完美!
定
义
p
r
i
m
e
[
i
]
[
j
]
表
示
第
i
个
数
字
的
质
因
子
j
的
个
数
。
定义prime[i][j]表示第i个数字的质因子j的个数。
定义prime[i][j]表示第i个数字的质因子j的个数。
定
义
m
t
[
i
]
表
示
质
因
子
i
的
个
数
的
有
序
序
列
。
定义mt[i]表示质因子i的个数的有序序列。
定义mt[i]表示质因子i的个数的有序序列。
所
以
当
每
个
数
字
都
有
i
这
个
因
子
时
,
即
:
所以当每个数字都有i这个因子时,即:
所以当每个数字都有i这个因子时,即:
i
f
(
m
t
[
i
]
.
s
i
z
e
(
)
=
=
n
)
∗
m
t
[
i
]
.
b
e
g
i
n
(
)
即
为
质
因
子
i
的
最
小
值
贡
献
。
if(mt[i].size() == n) \;*mt[i].begin()即为质因子i的最小值贡献。
if(mt[i].size()==n)∗mt[i].begin()即为质因子i的最小值贡献。
每 次 操 作 一 次 的 时 候 , 先 对 x 质 因 子 分 解 , 然 后 对 每 个 质 因 子 操 作 , 并 维 护 m t [ i ] 。 每次操作一次的时候,先对x质因子分解,然后对每个质因子操作,并维护mt[i]。 每次操作一次的时候,先对x质因子分解,然后对每个质因子操作,并维护mt[i]。
所 以 暴 力 模 拟 这 个 过 程 即 可 。 所以暴力模拟这个过程即可。 所以暴力模拟这个过程即可。
Code
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
#define endl "\n"
const ll mod = 1e9 + 7;
const int N = 2e5 + 10;
ll quick_pow(ll a, ll b) {
ll ans = 1;
while(b) {
if(b & 1) ans = ans * a % mod;
a = a * a % mod;
b >>= 1;
}
return ans % mod;
}
bool is_prime[N];
int prime[N];
void init() {
for(int i = 2;i < N; i++) {
if(!is_prime[i]) {
for(int j = 1;i * j < N; j++) {
prime[i * j] = i;
is_prime[i * j] = 1;
}
}
}
}
map<int, int> primes[N];
multiset<int> mt[N];
void solve() {
init();
int n, q; cin >> n >> q;
for(int i = 1;i <= n; i++) {
int x; cin >> x;
while(x > 1) {
primes[i][prime[x]]++;
x /= prime[x];
}
for(auto &it : primes[i]) {
mt[it.first].insert(it.second);
}
}
ll ans = 1;
for(int i = 1;i < N; i++) {
if(mt[i].size() == n) {
ans = ans * quick_pow(i, *mt[i].begin()) % mod;
}
}
while(q--) {
int i, x; cin >> i >> x;
map<int, int> cnt;
while(x > 1) {
cnt[prime[x]]++;
x /= prime[x];
}
for(auto &it : cnt) {
if(primes[i].find(it.first) == primes[i].end()) {
primes[i][it.first] = it.second;
mt[it.first].insert(it.second);
if(mt[it.first].size() == n) {
ans = ans * quick_pow(it.first, *mt[it.first].begin()) % mod;
}
}
else {
int pre = primes[i][it.first];
int cur = pre + it.second;
int premin = *mt[it.first].begin();
mt[it.first].erase(mt[it.first].find(pre));
mt[it.first].insert(cur);
int nowmin = *mt[it.first].begin();
primes[i][it.first] = cur;
if(mt[it.first].size() == n) {
ans = ans * quick_pow(it.first, nowmin - premin) % mod;
}
}
}
cout << ans << endl;
}
}
signed main() {
solve();
}