codeforces 547c// Mike and Foam// Codeforces Round #305(Div. 1)

本文介绍了一种算法,通过质因数分解处理数组中的元素,并计算每加入一个新元素后,得到的最大公约数(GCD)为1的不同组合数量。此算法适用于数据范围较小的情况。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题意:给出数组arr和一个空数组dst。从arr中取出一个元素到dst为一次操作。问每次操作后dst数组中gcd等于1的组合数。
由于数据都小于10^6,先将10^6以下的数分解质因数。具体来说从2开始,将2的倍数全部加2因子(用的vector),3的倍数加3因子。4不是质数,它的倍数不加因子。

还要一个cnt数组记录dst中有几个数是数组下标的倍数。

在放入元素x到dst数组,对于它的每个质因数及质因数间的乘积,看cnt中的量。组合数的增量为dst的sz(size)-(cnt[x的质因数])(即dst中和x都有x的质因数,因此要减)+(cnt[x的两个质因数的乘积])......然后再对x的素因子及成绩在cnt上加1.

乱码:

//#pragma comment(linker,"/STACK:1024000000,1024000000") 
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
#include <stack>
#include <list>
using namespace std;
const int SZ=1000010,INF=0x7FFFFFFF;
typedef long long lon;
const double EPS=1e-9;
vector<lon> fen[SZ];
bool used[SZ];
lon cnt[SZ];

void init(lon n)
{
    for(int i=2;i<n;++i)
    {
        if(fen[i].empty())
        for(int j=i;j<n;j+=i)
        {
            fen[j].push_back(i);
        }
    }
}

void add(vector<lon> &vct,bool type)
{
    lon sz=vct.size();
    for(lon i=0;i<(1<<sz);++i)
    {
        lon res=1;
        for(lon j=0;j<6;++j)
        {
            if(i&(1<<j))
            {
                res*=vct[j];
            }
        }
        if(type)++cnt[res];
        else --cnt[res];
    }
}

lon work(vector<lon> &vct)
{
    lon ans=0;
    lon sz=vct.size();
    //cout<<" "<<sz<<endl;
    for(lon i=1;i<(1<<sz);++i)
    {
        lon res=1;
        lon co=1;
        for(lon j=0;j<6;++j)
        {
            if(i&(1<<j))
            {
                res*=vct[j];
                co*=-1;
            }
        }
        ans+=co*cnt[res];
    }
    return ans;
}

int main()
{
    std::ios::sync_with_stdio(0);
    //freopen("d:\\1.txt","r",stdin); 
    lon n,m;
    cin>>n>>m;
    vector<lon> vct(n);
    for(int i=0;i<n;++i)
    {
        cin>>vct[i];
    }
    
    init(5e5+10);
    lon num=0;
    lon last=0;
    for(int i=0;i<m;++i)
    {
        lon id;
        cin>>id;
        --id;
        lon res=0;
        if(!used[id])
        {
            res+=work(fen[vct[id]]);
            //cout<<" "<<res<<endl;
            add(fen[vct[id]],1);
            used[id]=1;
            res=last+res+num;
        }
        else
        {
            res=last;
            add(fen[vct[id]],0);
            lon val=work(fen[vct[id]]);
            //cout<<" "<<val<<endl;
            res-=num-1+work(fen[vct[id]]);
            //cout<<" "<<res<<endl;
            used[id]=0;
        }
        cout<<res<<endl;
        if(used[id])++num;
        else --num;
        last=res;
    }
    return 0;
}

 

转载于:https://www.cnblogs.com/gaudar/p/9674840.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值