题意:已知一个长度为 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;
}
永不放弃!~。~