CF1097F Alex and a TV Show

Link
对每个集合维护其\(a_i\)表示有多少数是\(i\)的倍数。显然这个\(a\)数组与可重集一一对应。
第一种操做我们先预处理出\(d_{i,j}\)表示\(i\)是否为\(j\),那么就变成了把\(d_v\)赋给\(a_x\)
第二种操作就变成了\(a\)相加。
第三种操作就变成了\(a\)相乘。(\(i|gcd(a,b)\Leftrightarrow i|a\wedge i|b\)
第四种操作答案就是\(\sum\limits_{v|u}a_u\mu(\frac uv)\)
因为我们只关心对\(2\)取模的结果,那么我们显然可以用bitset来做。
第一种操作依旧是预处理然后直接赋值。
第二种操作就是异或。
第三种操作就是与。
第四种操作我们可以先筛出莫比乌斯函数,再预处理\(mu_{i,i*j}=\mu(j)\),然后答案就是\(mu_v\cap a_x\),再看这个里面的\(1\)的个数就好了。

#include<bits/stdc++.h>
using namespace std;
namespace IO
{
    char ibuf[(1<<21)+1],obuf[(1<<21)+1],*iS,*iT,*oS=obuf,*oT=obuf+(1<<21);
    char Get(){return (iS==iT? (iT=(iS=ibuf)+fread(ibuf,1,(1<<21)+1,stdin),(iS==iT? EOF:*iS++)):*iS++);}
    void Flush(){fwrite(obuf,1,oS-obuf,stdout),oS=obuf;}
    void Put(char x){*oS++=x;if(oS==oT)Flush();}
    int read(){int x=0,c=Get();while(!isdigit(c))c=Get();while(isdigit(c))x=x*10+c-48,c=Get();return x;}
}
using namespace IO;
const int N=100007,M=7007,lim=7000;
bitset<M>a[N],Mu,d[M],mu[M];
int main()
{
    int n=read(),Q=read(),x,y,z;
    for(Mu.set(),x=2;x*x<=lim;++x) for(y=1;x*x*y<=lim;++y) Mu[x*x*y]=0;
    for(x=1;x<=lim;++x) for(y=1;x*y<=lim;++y) d[x*y][x]=1,mu[x][x*y]=Mu[y];
    while(Q--)
	switch(read())
	{
	case 1:x=read(),y=read(),a[x]=d[y];break;
	case 2:x=read(),y=read(),z=read(),a[x]=a[y]^a[z];break;
	case 3:x=read(),y=read(),z=read(),a[x]=a[y]&a[z];break;
	case 4:x=read(),y=read(),Put(48+((a[x]&mu[y]).count()&1));break;
	}
    return Flush(),0;
}
posted @ 2019-10-23 17:26  Shiina_Mashiro  阅读(166)  评论(0编辑  收藏  举报