Codeforces Round #705 (Div. 2) D. GCD of an Array 质因子分解 + stl维护

传送门

题意: n n n个数,让后 q q q个操作,每次选择一个位置的数使其乘 x x x,每次询问后输出所有数的 g c d gcd gcd

思路: 这个题思路算是比较好想的。首先就是一个计算方式即计算所有数的 g c d gcd gcd,这个比较容易想到当一个质因数 x x x在每个数出现次数 > = 1 >=1 >=1的时候,设出现幂数是 c 1 , c 2 , . . . , c n c_1,c_2,...,c_n c1,c2,...,cn,他对 g c d gcd gcd的贡献为 x m i n ( c 1 , c 2 , . . . , c n ) x^{min(c_1,c_2,...,c_n)} xmin(c1,c2,...,cn)。让后对于乘操作,可以发现 g c d gcd gcd是单调不减的,所以我们可以递推下去。让后比较显然的就是维护每个质因子在数组 n n n中出现的次数,每次取 m i n min min,让后就会想到对于每个质因子建一颗线段树,但是显然是不行的,空间直接炸掉了。所以需要考虑用其他东西维护,题解是用 m u l t i s e t multiset multiset维护的, s t l stl stl真香
让后就是实现的细节了,当 m u l t i s e t multiset multiset的大小为 n n n的时候才能更新,更新的时候取最小值,由于 m u l t i s e t multiset multiset是自己排序的,所以直接取头部的元素即可。让后更新的时候需要看看是否之前已经更新了一部分 m i mi mi,如果更新过了要从 m i + 1 mi+1 mi+1 c n t cnt cnt更新。
还是对 m u l t i s e t multiset multiset不熟悉,比赛想到了用但是不会用
最后优化的一点就是 l o g n logn logn分解质因子。

//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#define X first
#define Y second
#define L (u<<1)
#define R (u<<1|1)
#define pb push_back
#define mk make_pair
#define Mid (tr[u].l+tr[u].r>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;

//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
//void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }

typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;

const int N=1000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;

int n,q;
int a[N],nt[N];
multiset<int>s[N];//s[i]表示质因子i在数组中的分布
map<int,int>mp[N];//mp[i][j]表示第i个数的质因子j的个数
bool st[N];
LL ans=1;

void add(int id,int x)
{
    
    
    while(x!=1)
    {
    
    
        int div=nt[x],cnt=0;
        while(div==nt[x]) cnt++,x/=nt[x];
        int mi;
        if(s[div].size()==n) mi=*s[div].begin();
        else mi=0;
        if(mp[id][div]==0)
        {
    
    
            s[div].insert(cnt),mp[id][div]+=cnt;
            if(s[div].size()==n)
            {
    
    
                int cnt=*(s[div].begin());
                for(int i=mi+1;i<=cnt;i++) ans=ans*div%mod;
            }
        }
        else
        {
    
    
            int t=mp[id][div]; mp[id][div]+=cnt;
            s[div].erase(s[div].find(t));
            s[div].insert(mp[id][div]);
            if(s[div].size()==n)
            {
    
    
                int cnt=*(s[div].begin());
                for(int i=mi+1;i<=cnt;i++) ans=ans*div%mod;
            }
        }

    }
}

int main()
{
    
    
//	ios::sync_with_stdio(false);
//	cin.tie(0);

    for(int i=2;i<N;i++)
    {
    
    
        if(st[i]) continue;
        nt[i]=i;
        for(int j=i+i;j<N;j+=i)
            st[j]=true,nt[j]=i;
    }
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)
    {
    
    
        int x; scanf("%d",&x);
        add(i,x);
    }
    while(q--)
    {
    
    
        int x,id; scanf("%d%d",&id,&x);
        add(id,x);
        printf("%lld\n",ans);
    }



	return 0;
}
/*

*/



猜你喜欢

转载自blog.csdn.net/m0_51068403/article/details/114477289
今日推荐