cf-round706-div2-D/map/multiset/gcd/素数筛
https://codeforces.ml/contest/1493/problem/D 《题目来源》
题目特征:
2e5个位点,2e5以内的数字,2e5的操作并询问。
特点:
2e5以内的数字:数字的质因数情况能够预处理
这题我不是很懂,非常不懂。
cf上面的题解看不懂,对着标称学习吧。 https://codeforces.ml/blog/entry/88422 《题解》
#include <bits/stdc++.h> using namespace std; typedef long long ll; int const maxn = 2e5 + 5, max_val = 2e5 + 5; ll mod = 1e9 + 7, ans = 1; int nxt[max_val], n; multiset <int> cnt[max_val]; map <int, int> cnt_divisor[maxn]; void add(int i, int x) { while (x != 1) { int div = nxt[x], add = 0; while (nxt[x] == div) add++, x = x / nxt[x]; int lst = cnt_divisor[i][div]; cnt_divisor[i][div] += add; int lst_min = 0; if ((int)cnt[div].size() == n) { lst_min = (*cnt[div].begin()); } if (lst != 0) { cnt[div].erase(cnt[div].find(lst)); } cnt[div].insert(lst + add); if ((int)cnt[div].size() == n) { for (int j = lst_min + 1; j <= (*cnt[div].begin()); ++j) { ans = ans * (ll)div % mod; } } } } main() { ios_base::sync_with_stdio(0); cin.tie(0); int q, l, x; cin >> n >> q; for (int i = 2; i < maxn; ++i) { if (nxt[i] == 0) { nxt[i] = i; if (i > 10000) continue; for (int j = i * i; j < maxn; j += i) { if (nxt[j] == 0) nxt[j] = i; } } } for (int i = 1; i <= n; ++i) { cin >> x; add(i, x); } for (int i = 1; i <= q; ++i) { cin >> l >> x; add(l, x); cout << ans << '\n'; } return 0; }
大概摸清了几个部分:
一、预处理:由欧拉筛演变
在筛的基础上,给2e5的每个数字预处理出其最小的素因数,记为nxt[i]。
二、把初始状态与询问状态统一处理
初始状态视为无需输出的操作
三、了解一下map与multiset
map https://www.cnblogs.com/yonglin1998/p/11780828.html
为了获得一个动态大小的二维数组。map<int, int>cnt_divisor[maxn]
multiset https://blog.csdn.net/sodacoco/article/details/84798621
看做一个自动维护(log n)的序列,st.insert(5), st.begin(), st.end(), st.erase(st.begin()), st.find(5)
四、思路比较简单
对于每个询问,(借用nxt【】)一个质数一个质数地处理因数
先统计贡献了多少个质数k,然后把k存入统计列表,
若满足n个位点在该质因数上都有贡献,则让ans乘其最小个数。
ans递增,每次乘那个质因数即可。