codeforces round #705 div2 D. GCD of an Array multiset与质因数分解

codeforces round #705 div2 D. GCD of an Array multiset与质因数分解


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

题意

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

思路

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

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值。 multisetmin
因 为 m u l t i s e t 每 次 操 作 都 是 log ⁡ n , 而 且 m t l t i s e t 内 部 都 是 有 序 的 , 可 重 复 的 , 简 直 完 美 ! 因为multiset每次操作都是\log n,而且mtltiset内部都是有序的,可重复的,简直完美! multisetlognmtltiset

定 义 p r i m e [ i ] [ j ] 表 示 第 i 个 数 字 的 质 因 子 j 的 个 数 。 定义prime[i][j]表示第i个数字的质因子j的个数。 prime[i][j]ij
定 义 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]。 xmt[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();
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值