Codeforces Round #705 (Div. 2) D. GCD of an Array

传送门

题目大意

你会得到一个数组a,并且会有q个查询,给定两个数字i和x,将a[i]乘以x,输出每次查询后的数组a的gcd

题解

牛客的寒假训练营有一道比这个简单的同类型题,这里上个牛客的传送门,我们先考虑如果数组a没有被修改,应该怎么求他们的gcd,很显然,我们可以将每个数字进行质因子分解,这样数组a中所有数都有的质因子,一定就是他们的gcd的质因子。再考虑如果有修改会怎么样,如果a[i]乘x,将x也质因子分解,如果分解出的质因子,别的数字也有,并且别的数字的此质因子数量均大于a[i]*x的此质因子数量,那么gcd的此质因子也可以多一个,换句话说,gcd可以扩大此质因子倍。由此我们得出解法,用multiset存每一个数的对应质因子的数量,然后判断是否其中每个质因子的最小值是否扩大就好了,上代码

#include<cstdio>
#include<cstdio>
#include<map>
#include<set>
#define MAX 1005
#define MAXN 200005
using namespace std;
const long long MOD=1e9+7;
int findprim[MAX];
int prim[MAX];
int primnum;
map<int,int> all_prim[MAXN];
multiset<int>cnt[MAXN];
long long ans=1;
void init(){
    findprim[0]=findprim[1]=1;
    for(int i=2;i<=MAX;i++){
        if(!findprim[i]){
            for(int j=i+i;j<=MAX;j+=i){
                findprim[j]=1;
            }
        }
    }
    for(int i=2;i<=MAX;i++){
        if(!findprim[i]){
            prim[primnum++]=i;
        }
    }
    return ;
}
void tryans(int prim,int n,int size){
	if(cnt[prim].size()<n){
		return ;
	}
	for(int i=0;i<size;i++){
		ans*=prim;
		ans%=MOD;
	}
	return ;
}
int main(){
    init();
    int n,q,a,m;
    scanf("%d%d",&n,&q);
    for(int i=0;i<n;i++){
    	scanf("%d",&a);
    	for(int j=0;prim[j]*prim[j]<=a&&j<primnum;j++){
    		int flag=0;
    		while(!(a%prim[j])){
    			all_prim[i][prim[j]]++;
    			a/=prim[j];
    			flag=1;
			}
			if(flag){
				cnt[prim[j]].insert(all_prim[i][prim[j]]);
				tryans(prim[j],n,*cnt[prim[j]].begin());
			}
		}
		if(a!=1){
			all_prim[i][a]++;
			cnt[a].insert(1);
			tryans(a,n,*cnt[a].begin());
		}
	}
	for(int i=0;i<q;i++){
		scanf("%d%d",&m,&a);
		m--;
		for(int j=0;prim[j]*prim[j]<=a&&j<primnum;j++){
    		int flag=0,flag2=0,thisnum=0;
    		while(!(a%prim[j])){
				all_prim[m][prim[j]]++;
				if(all_prim[m][prim[j]]==1){
    				flag2=1;
				}
    			a/=prim[j];
    			flag=1;
    			thisnum++;
			}
			if(flag){
				int min;
				if(flag2){
					min=0;
				}else{
					min=*cnt[prim[j]].begin();
					cnt[prim[j]].erase(cnt[prim[j]].find(all_prim[m][prim[j]]-thisnum));	
				}
				cnt[prim[j]].insert(all_prim[m][prim[j]]);
				tryans(prim[j],n,*cnt[prim[j]].begin()-min);
			}
		}
		if(a!=1){
			int min;
			all_prim[m][a]++;
			if(all_prim[m][a]==1){
				min=0;
			}else{
				min=*cnt[a].begin();
				cnt[a].erase(cnt[a].find(all_prim[m][a]-1));
			}
			cnt[a].insert(all_prim[m][a]);
			tryans(a,n,*cnt[a].begin()-min);
		}
		printf("%lld\n",ans);
	}
	return 0;
}

有一说一,感觉D比C简单呀Q^Q,如果解释的有误,欢迎指正

上一篇:最小生成树——Prim And Kruskal实现最小生成树


下一篇:最小生成树(C语言, prim算法)