Codeforces 547C

来源:互联网 发布:音乐裁切软件 编辑:程序博客网 时间:2024/06/16 03:38

在这个题用容斥做的过程中从别人的博客学到了一些有趣的处理方法(好吧,其实是我太菜了,那种方法我之前没见过)。。。。。。

思路:先预处理出每个数的质因子然后对于每一个操作数算出与它互质的数的个数再加加减减。。。。。。详见代码,可能有说不清楚或者搞错的地方,望指正

#include <iostream>#include <algorithm>#include <vector>#include <stack>#include <string.h>#include <cstdio>#include <map>#include <queue>#include <math.h>#include <cstring>#include <set>#define pb push_back#define fi first#define se second#define INF 0x3f3f3f3fusing namespace std;typedef long long LL;const LL MOD=1e9+7;const double eps=1e-9;const LL MAXN=500000+23;LL prime[MAXN],total;bool isprime[MAXN],odd[MAXN],vis[MAXN];LL fac[MAXN][30],sum[MAXN];//fac[i][0]:i的质因子的个数,fac[i][j]:i的第j个质因子void make(){    LL m=MAXN-3;    total=0;    memset(isprime,true,sizeof(isprime));    isprime[1]=isprime[0]=false;    for(LL i=2;i<=m;i++)    {        if(isprime[i])prime[++total]=i;        for(LL j=1;j<=total&&i*prime[j]<=m;j++)        {            isprime[i*prime[j]]=false;            if(i%prime[j]==0)break;        }    }}LL n,q,a[MAXN];int main(){    make();    memset(odd,false,sizeof(odd));    for(LL i=2;i<MAXN-3;i++)    {        fac[i][0]=0;        LL x=i;        for(LL j=1;j<=total&&prime[j]*prime[j]<=x;j++)        {            if(x%prime[j]==0)fac[i][++fac[i][0]]=prime[j];            while(x%prime[j]==0)x/=prime[j];        }        if(x>1)fac[i][++fac[i][0]]=x;        LL len=1<<fac[i][0];        for(LL j=1;j<len;j++)        {            LL s=0,t=1;            for(LL k=0;k<fac[i][0];k++)            {                if(j&(1<<k)){s++;t*=fac[i][k+1];}            }            if(s&1)odd[t]=true;        }    }    while(scanf("%lld%lld",&n,&q)!=-1)    {        for(LL i=0;i<n;i++)scanf("%lld",&a[i]);        memset(vis,false,sizeof(vis));        memset(sum,0,sizeof(sum));LL ans=0,m=0;        for(;q--;)        {            LL x,len=0;            scanf("%d",&x);            if(!vis[x])            {                vis[x]=true;                x=a[x-1];                len=1<<fac[x][0];                m++;                LL res=m-1;                for(LL j=1;j<len;j++)                {                    LL t=1;                    for(LL k=0;k<fac[x][0];k++)                    {                        if(j&(1<<k)){t*=fac[x][k+1];}                    }                    if(odd[t])                    {                        res-=sum[t];                    }                    else res+=sum[t];                    sum[t]++;                }                ans+=res;            }            else            {                vis[x]=false;                x=a[x-1];                len=1<<fac[x][0];                m--;                LL res=m;                for(LL j=1;j<len;j++)                {                    LL t=1;                    for(LL k=0;k<fac[x][0];k++)                    {                        if(j&(1<<k)){t*=fac[x][k+1];}                    }                    if(odd[t])                    {                        res-=(sum[t]-1);                    }                    else res+=(sum[t]-1);//减1表示他自己不算                    sum[t]--;                }                ans-=res;            }//res:要加入(去掉)的当前的这个数与其他的数互质的个数            printf("%lld\n",ans);        }    }    return 0;}


0 0