Codeforces 1097F. Alex and a TV Show

传送门

由于只要考虑 $\mod 2$ 意义下的答案,所以我们只要维护一堆的 $01$ 

容易想到用 $bitset$ 瞎搞...,发现当复杂度 $qv/32$ 是可以过的...

一开始容易想到对每个集合开一个 $bitset$ ,叫 $cnt[]$ ,维护各种值的数出现了奇数还是偶数次

因为要维护那个奇怪的 $3$ 操作,所以改成维护各种值的倍数出现了奇数还是偶数次,即

$cnt[x]$ 维护集合内所有 $x|d$ 的数 $d$ 的出现次数

那么对于操作 $3$,$x$ 的倍数和 $y$ 的倍数相乘后 $x$ 的倍数和 $y$ 的倍数数量都是 $cnt[x] \cdot cnt[y]$

然后就可以很容易维护了,因为只有 $0,1$ 那么其实相当于把两个 $bitset$ 取 $\text{'&'}$ 即可

同时对于操作 $2$ ,显然只要对 $bitset$ 取 $\text{'^'}$ 就行

然后操作 $1$ ,直接把 $bitset$ 清空,然后设集合内的数为 $d$ ,那么直接根号筛一下 $d$ 的因数 $x$ 然后 $cnt[x]=1$ 即可

最后是操作 $4$ ,因为我们维护的是 $x$ 的倍数的出现次数,设 $F(x),f(x)$ 分别为 $x$ 倍数出现次数,$x$ 出现次数

那么有 $F(x)=\sum_{x|d} f(d)$ ,然后就发现了熟悉的莫比乌斯反演,我们知道 $F$ 想求 $f$,直接反演可得

$f(x)=\sum_{x|d} \mu (\frac{d}{x}) F(d)$ ,由于 $\mod 2$ 意义下 $-1 \equiv 1$ 所以可以用 $bitset$ 维护一下每个 $x$ 的所有 $x|d$ 的 $\mu(d/x)$

即设 $bitset$ $g[x]$ 维护一下 $x|d$ 的 $g[x][d]=\mu(d/x)$ 然后对于 $4$ 操作 $(4\ x\ v)$ 就是 $(cnt[x]&g[v]).count()&1$ 

代码不长

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<bitset>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=1e5+7,M=7007;
int n,Q;
int pri[M],mu[M],tot;
bool not_pri[M];
bitset <M> cnt[N],g[M];
void init()
{
    not_pri[1]=1; mu[1]=1;
    for(int i=2;i<M;i++)
    {
        if(!not_pri[i]) pri[++tot]=i,mu[i]=1;
        for(int j=1;j<=tot;j++)
        {
            ll g=1ll*i*pri[j]; if(g>=M) break;
            not_pri[g]=1; if(i%pri[j]==0) break;
            mu[g]=-mu[i];
        }
    }
    for(int i=1;i<M;i++)
        for(int j=i;j<M;j+=i)
            g[i][j]=abs(mu[j/i]);
}
int main()
{
    n=read(),Q=read(); init();
    int a,b,c,d;
    while(Q--)
    {
        a=read(),b=read(),c=read();
        if(a==1)
        {
            cnt[b]=0; int T=sqrt(c);
            for(int i=1;i<=T;i++)
                if(c%i==0) cnt[b][i]=cnt[b][c/i]=1;
        }
        else if(a==2) d=read(),cnt[b]=cnt[c]^cnt[d];
        else if(a==3) d=read(),cnt[b]=cnt[c]&cnt[d];
        else printf("%d",int((cnt[b]&g[c]).count())&1);
    }
    puts(""); return 0;
}

 

上一篇:Java(BitSet.class)中的OR操作


下一篇:8.21