codeforces round

传送门:https://codeforces.com/contest/1493/problem/D

题意

给一个长度为n的序列,有q个操作,每次操作会将第i个数乘x,在输出gcd(所有数).

思路

因为每次操作只对一个数操作,而不是区间修改,而且是不是求区间gcd。 即不需要用线段树求区间gcd,可以用可以动态开点维护每个质因子的min值。

$gcd=p_1^{min(k_1,k_2…k_n)}…p_n^{min(k_1,k_2…k_n)}$

本篇题解是利用multiset维护每个质因子的min值。 因为multiset每次操作都是$\log n$,而且mtltiset内部都是有序的,可重复的,简直完美!

定义prime[i][j]表示第i个数字的质因子j的个数。 定义mt[i]表示质因子i的个数的有序序列。 所以当每个数字都有i这个因子时,即: $if(mt[i].size() == n) \;*mt[i].begin()$即为质因子i的最小值贡献。

每次操作一次的时候,先对x质因子分解,然后对每个质因子操作,并维护mt[i]。

所以暴力模拟这个过程即可。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
##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();
}

本文作者:jujimeizuo
本文地址https://blog.jujimeizuo.cn/2021/03/07/codeforces-round-705-div2-d-g/
本博客所有文章除特别声明外,均采用 CC BY-SA 3.0 协议。转载请注明出处!