Codeforces1493D GCD of an Array

题目链接

点我跳转

题目大意

给定一个长度为 (N) 的序列 (A)

(Q) 次操作,每次操作给定两个数 (i) , (X),使得 (A[i] = A[i] imes X)

问每次操作后整个序列的 (gcd) 为多少 (对 (1e9+7) 取模)

解题思路

显然 (gcd) 不满足同余定理 ( (gcd(4,6) \% 3) (!=) (gcd(4\%3,6)\%3) )

(A[i])(X) 最大值都不超过 (2e5) , 所以可考虑质因子分解

首先要知道对于一个数它的质因子个数是 (log) 级别的

有个贪心的证明方法

要让一个数的质因子最多,那这个数的质因子就应该尽可能小

那么就让他的质因子为 (2,3,5,7,11,13,...)

那么它就等于 (2 × 3 × 5 × 7 × 11 × 13 ×...)

当乘到 (29) 时,它已经大于 (6e9) 了,所以一个数的质因子个数是 (log) 级别的

于是可以用 (map) 开个二维动态数组 (f[i][j])(f[i][j]) 表示 (a[i]) 的质因子 (j) 的幂次

这样使用的空间最多为 ((N + Q) × log)

对于一个质数 (P) ,它对答案产生贡献的条件是: $A[1] $ ~ (A[N]) 的质因子都包含 (P)

也就是 (P) 作为质因子一共出现了 (N) 次,而它的贡献显然是出现过的最小幂次

于是可以对每个质数 (p) 开个 (set)

(A[i]) 的质因子包含 (p) 时,往 (set[p]) 里插入对应的幂次

而当 (set[p].size() =n) 时,(p) 就会对答案产生 (p^{set[p].begin() - pre[p]}) 贡献

其中 (pre[p]) 表示上一次 (p) 对答案产生的贡献,其初始值为 (0)

AC_Code

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll pow_mod(ll x,ll n,ll mod)
{
	ll res = 1;
	while(n)
	{
		if(n & 1) res = res * x % mod;
		x = x * x % mod;
		n >>= 1;
	}
	return res;
}

int prime[200010] , minprime[200010];

int euler(int n)
{
	int c = 0 , i , j;
	
	for(i = 2 ; i <= n ; i ++)
	{
		if(!minprime[i]) prime[++ c] = i , minprime[i] = i;
		
		for(j = 1 ; j <= c && i * prime[j] <= n ; j ++)
		{
			minprime[i * prime[j]] = prime[j];
			
			if(i % prime[j] == 0) break ;
		}
	}
	return c;
}

const ll mod = 1e9 + 7;
 
const int N = 3e5 + 10;

int n , q , I , X , a[N] , pre[N];

map<int , int>f[N];

multiset<int>se[N];

signed main()
{	
	ios::sync_with_stdio(false);
	
	cin.tie(0) , cout.tie(0);

	int sum = euler(200000);
	
	ll gcdd = 1;

	cin >> n >> q;

	for(int i = 1 ; i <= n ; i ++) cin >> a[i];

	for(int i = 1 ; i <= n ; i ++)
	{
		for(int j = 2 ; j * j <= a[i] ; j ++) if(a[i] % j == 0)
		{
			int c = 0;

			while(a[i] % j == 0) a[i] /= j , c ++ ;

			f[i][j] = c;

			se[j].insert(c);
		}
		
		if(a[i] > 1) f[i][a[i]] = 1 , se[a[i]].insert(1);
	}

	for(int i = 1 ; i <= sum ; i ++)
	{
		int p = prime[i];

		if(se[p].size() == n)
		{
			auto j = *se[p].begin();

			gcdd = gcdd * pow_mod(1LL * p , 1LL * j , mod) % mod;

			pre[p] = j;
		}
	}
	
	while(q --)
	{
		cin >> I >> X;

		for(int j = 1 ; prime[j] * prime[j] <= X && j <= sum ; j ++) if(X % prime[j] == 0)
		{
			int c = 0 , p = prime[j];

			while(X % p == 0) X /= p , c ++ ;

			if(f[I].count(p))
			{
				auto it = se[p].find(f[I][p]);

				se[p].erase(it);
			}

			f[I][p] += c;
	
			se[p].insert(f[I][p]);

			if(se[p].size() == n)
			{
				auto it = *se[p].begin();

				gcdd = gcdd * pow_mod(p , it - pre[p] , mod) % mod;

				pre[p] = it;
			}
		}
		if(X > 1)
		{
			if(f[I].count(X))
			{
				auto it = se[X].find(f[I][X]);
				
				se[X].erase(it);
			}
			
			f[I][X] += 1;
			
			se[X].insert(f[I][X]);
			
			if(se[X].size() == n)
			{
				auto it = *se[X].begin();

				gcdd = gcdd * pow_mod(X , it - pre[X] , mod) % mod;

				pre[X] = it;

			}
		}
		cout << gcdd << '
';
	}
	return 0;
}
凡所不能将我击倒的,都将使我更加强大
原文地址:https://www.cnblogs.com/StarRoadTang/p/14494421.html