cf1493D

传送门

比赛时看了这道题,感觉自己能做出来,奈何对STL的应用不到位,硬是想不起来multiset,没有打出来,赛后看到了题解用的mutiset瞬间来了思路。

我们建立一个\(map<int,int>mp[maxm]\)
\(mp[i][j]\)表示在位置\(i\)上的数质因子分解后质因子\(j\)的次方数为\(mp[i][j]\)

建立\(multiset<int>S[maxm]\),其中\(S[i]\)中储存质因数\(i\)在所有位置中存在的次方数,当且仅当\(S[i]\)中元素个数为\(n\)时,\(n\)个数的公因数包含\(i^{(*S[i].begin())}\)

因此如果当前位置\(i\)不包含质因子\(j\),直接将\(j\)加入即可,然后判断是否当前所有位置都包含\(j\),计算答案。如果当前已包含\(j\),如果当前\(j\)已经包含了\(n\)个位置,那么我们需要记录修改之前最小的次方值与修改之后最小的次方值,然后修改相应的值即可。

这样我们只需对每一个数进行质因数分解即可,s时间复杂度\(O(n*\sqrt{n})\)可以解决问题


int n,q;
ll ans=1;
int p[maxn],cnt;
bool vis[maxm];

multiset<int>S[maxm];//s[i]表示具有因子p[i]位置的次方数
map<int,int>mp[maxm];//mp[i][j]表示位置i上的数包含质数p[j]的mp[i][j]次方


void pre(){
    n=2e5;cnt=0;
    rep(i,2,n){
        if(!vis[i]) p[++cnt]=i;
        rep(j,1,cnt){
            if(1LL*i*p[j]>n) break;
            vis[i*p[j]]=1;
            if(i%p[j]==0) break;
        }
    }
}
ll qpow(ll a,ll b){
    ll sum=1;
    while(b){if(b&1)sum=sum*a%mod;a=a*a%mod;b>>=1;}
    return sum;
}
void add(int pos,int val){
    int now=1;
    while(val>1){
        if(now*now>val) break;
        int num=0;
        while(val%p[now]==0){
            num++;val/=p[now];
        }
        if(num==0) {now++;continue;}
        if(!mp[pos][now]){//pos位置不包含这个因子
            mp[pos][now]=num;
          //  cout<<now<<" "<<num<<endl;
            S[now].insert(num);

            if(S[now].size()==n) 
                ans=ans*qpow(p[now], (*S[now].begin()) )%mod;
        }
        else{
            int last=*S[now].begin();
            S[now].erase(S[now].find(mp[pos][now]));
            mp[pos][now]+=num;
            S[now].insert(mp[pos][now]);
            int fir=*S[now].begin();
            if(S[now].size()==n)ans=ans*qpow(p[now],fir-last)%mod;;
        }
        now++;
    }
    if(val>1){
        int x=lower_bound(p+1,p+1+cnt,val)-p;
        if(!mp[pos][x]) {
            mp[pos][x]=1;S[x].insert(1);
            if(S[x].size()==n) 
                ans=ans*qpow(p[x], (*S[x].begin()) )%mod;
        }
        else{
            int last=*S[x].begin();
            S[x].erase(S[x].find(mp[pos][x]));
            mp[pos][x]++;
            S[x].insert(mp[pos][x]);
            int fir=*S[x].begin();
            if(S[x].size()==n)ans=ans*qpow(p[x],fir-last)%mod;;
        }
    }
}

int main(){
    pre();
    n=read(),q=read();
    int x,y;
    rep(i,1,n){
        x=read();
        add(i,x);
    }
    rep(i,1,q){
        x=read(),y=read();
        add(x,y);
        print(ans);pts;
    }
    return 0;
}

在看了题解之后,我发现质因数分解的部分可以优化,不妨令\(p[i]\)表示\(i\)的最小质因数,那么就可以直接转移了,不用再枚举质因数了

int n,q;
ll ans=1;
int p[maxm];
multiset<int>S[maxm];//s[i]表示具有因子p[i]位置的次方数
map<int,int>mp[maxm];//mp[i][j]表示位置i上的数包含质数p[j]的mp[i][j]次方


void pre(){
    n=2e5;
    rep(i,2,n){
        if(!p[i]) p[i]=i;
        for(int j=i*2;j<=n;j+=i) {
            if(!p[j]) p[j]=i;
        }
    }
}
ll qpow(ll a,ll b){
    ll sum=1;
    while(b){if(b&1)sum=sum*a%mod;a=a*a%mod;b>>=1;}
    return sum;
}
void add(int pos,int val){
    while(val>1){
        int num=0,div=p[val];
        while(val%div==0){
            num++;val/=div;
        }
        if(!mp[pos][div]){//pos位置不包含这个因子
            mp[pos][div]=num;
            S[div].insert(num);

            if(S[div].size()==n) 
                ans=ans*qpow(div, (*S[div].begin()) )%mod;
        }
        else{
            int last=*S[div].begin();
            S[div].erase(S[div].find(mp[pos][div]));
            mp[pos][div]+=num;
            S[div].insert(mp[pos][div]);
            int fir=*S[div].begin();
            if(S[div].size()==n)ans=1LL*ans*qpow(1LL*div,1LL*(fir-last))%mod;;
        }
    }
}

int main(){
    pre();
    n=read(),q=read();
    int x,y;
    rep(i,1,n){
        x=read();
        add(i,x);
    }
    rep(i,1,q){
        x=read(),y=read();
        add(x,y);
        print(ans);pts;
    }
    return 0;
}
posted @ 2021-03-08 23:59  Mr_cold  阅读(53)  评论(0编辑  收藏  举报