F - GCD of an Array

F - GCD of an Array

https://codeforces.ml/problemset/problem/1493/D

题意

首先给定长度为n的初始数组 有q次操作 每次操作输入 i v 代表给下标为i的数乘上v 每次询问求当前数组中的数的最大公因子(gcd)

思路

要求gcd 那肯定要分解质因子 可以用普通的素数筛也可以用欧拉筛(欧拉筛更快一点)
每个位置上的数的共同质因数乘起来就是gcd 我们可以确定gcd肯定是一直增加的
对于每个位置我们可以用一个二维mp 来记录 mp[p][i]就代表位置是p中质因数是i的个数
用multiset<>set[i]来储存素数为i的在不同位置当前出现过几次 当每个位置都有质因数i的时候 那就要对答案贡献 其中最小个数质数i
但是贡献完后无法将每个set都减去 下次质因数i的不同个数又到达了n就无法再操作了 那我们可以先除去更新前最小值i set中删去那个位置的值 然后更新mp 再插进set[i]里用于下次更新 取更新后set[i]的第一个值就是再乘以几个i(后面的个数就包括了前面更新的个数mp是一直增加的) 这里乘几个i和除几个i用快速幂和逆元表示
每次要判断mp[p]i中是否有值 没有值可以直接插入 有值的话要判断是否已经达到了n 达到了就要进行贡献处理
之所以用multiset是因为其可以重复且键值排序


#include<bits/stdc++.h>
#include<unordered_map>
#define ll long long
#define ull unsigned long long
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;

const ll inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-4;
const ll N = 2e5 + 5;
const int mod = 1e9 + 7;
ll n, q;
int isPrime[N];
vector<int> prime;
ll tot, ans = 1;
unordered_map<ll, ll> mp[N];
multiset<ll >st[N];
//快速幂
ll ksm(ll base, ll pow) {
    ll ans = 1;
    while (pow) {
        if (pow & 1) ans = ans * base % mod;
        base = base * base % mod;
        pow >>= 1;
    }
    return ans;
}

void work(ll t, ll p, ll cnt1) {
    if (mp[p].count(t)) {//出现过
        if (st[t].size() == n) {//达到了n个先除以贡献
            ll res = ksm(t, *st[t].begin());
            ans = (ans % mod * ksm(res, mod - 2)) % mod;
        }//更新 先去掉更新前的 再更新后插入更新了的
        st[t].erase(st[t].find(mp[p][t]));//st[i].find(mp[p][t])返回迭代器 
        mp[p][t] += cnt1;
        st[t].insert(mp[p][t]);
    }
    else {//没有出现过 直接加
        mp[p][t] = cnt1;
        st[t].insert(mp[p][t]);
    }//如果更新后再次满了 那就进行乘的贡献 
    if (st[t].size() == n) {
        ans = (ans % mod * ksm(t, *st[t].begin())) % mod;
    }

}

void getp2(ll x, ll p) {
    //找质因子
    for (int i = 2; i <= x / i; ++i) {
        if (!(x % i)) {
            int cnt1 = 0;
            while (x % i == 0) {
                x /= i;
                ++cnt1;
            }
            work(i, p, cnt1);
        }

    }
    if (x > 1) {
        work(x, p, 1);
    }
}
void solve() {
    cin >> n >> q;
    for (int i = 1, x; i <= n; i++) {
        cin >> x;
        getp2(x, i);
    }
    ll p, x;
    for (int i = 1; i <= q; i++) {
        cin >> p >> x;
        getp2(x, p);
        cout << ans << "\n";
    }
}

signed main() {
    IOS;
    //getprime();
    int t = 1;
    //cin >> t;
    while (t--) {
        solve();
    }

}
posted @ 2022-05-13 01:03  Yaqu  阅读(26)  评论(0)    收藏  举报