GCD of an Array

传送门

题意:已知一个长度为 n的数列 q 次操作,每次将ai​ 乘以 x,在每次操作后输出整个数列的 gcd。

思路:质因数思想,每次最小公共质因数的数量,这些数量相乘,最后的答案就是gcd

#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio(false)
#define endl '\n'
using namespace std;
typedef long long ll;
const int MAXN = 2e5 + 10;
const int mod = 1e9 + 7;
int n, q, ggcd = 1;
int a[MAXN];
map<int, int> mp[MAXN];
multiset<int> mul[MAXN];
int pre[MAXN];

long long fastPower(long long base, long long power) {
	long long result = 1;
	while (power > 0) {
		if (power & 1) {//此处等价于if(power%2==1)
			result = result * base % mod;
		}
		power >>= 1;//此处等价于power=power/2
		base = (base * base) % mod;
	}
	return result;
}


void add_count(int pos, int x, int countt)
{
	if (!mp[pos][x])	//如果当前这一位是的只有一个数的,直接加就行
	{
		mp[pos][x] += countt;
		mul[x].insert(countt);
		/*if (pos == 3 && x == 3)
			cout << mul[x].size() << endl;*/
		if (mul[x].size() == n)
		{
			auto it = mul[x].begin();	//对于迭代器和整数之间的转换,可以用无限的替换操作
			pre[x] = *it;	//记录下这个质因数的次数,方便修改的时候用
			ggcd = (ggcd % mod * fastPower(x, *it) % mod) % mod;
			
		}
	}
	else   //这里的情况就是修改值了, 注意到,修改一个,只要先把原先的删除,再原先的mp[pos][x]的基础上加countt, 在插入这样就可以实现维护作用, 
	{	
		ll temp = mp[pos][x];
		mul[x].erase(mul[x].find(temp));
		mp[pos][x] += countt;
		
		mul[x].insert(mp[pos][x]);
		if (mul[x].size() == n)
		{
			auto it = mul[x].begin();	//注意multiset的删除方式,如果删除的是值的,他会把,所有的这个值全删了,但是如果删除的的是一个迭代器,那么只会删除那一位
			int cha = *it - pre[x];	//pre数组是这道题的点睛之笔,pre记录这个质因数上回的最小值,因为这回的最小值只会比上回大或者相等,多出来的部分就是gcd要乘的部分
			ggcd = (ggcd % mod * fastPower(x, cha) % mod) % mod;
			pre[x] = *it;
		}
	}

}

void copy_with(int pos, int x)
{
	for (int i = 2; i <= sqrt(x); ++i)
	{
		if (x % i == 0)
		{
			int countt = 0;
			while (x % i == 0)
			{
				x /= i;
				countt++;
			}
			add_count(pos, i, countt);
		}
	}
	if (x != 1)
		add_count(pos, x, 1);
}

int main()
{
	//IOS; cin.tie(0), cout.tie(0);
	cin >> n >> q;
	for (int i = 1; i <= n; ++i)
	{
		cin >> a[i];
		copy_with(i, a[i]);
	}

	//cout << gcd << endl;

	while (q--)
	{
		int pos, x;
		cin >> pos >> x;

		copy_with(pos, x);
		cout << ggcd % mod << endl;
	}/**/
	return 0;
}

永不放弃!~。~

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值