• BZOJ5294 BJOI2018二进制(线段树)


      二进制数能被3整除相当于奇数、偶数位上1的个数模3同余。那么如果有偶数个1,一定存在重排方案使其合法;否则则要求至少有两个0且至少有3个1,这样可以给奇数位单独安排3个1。

      考虑线段树维护区间内的一堆东西,合并两节点时计算跨过区间中点的答案。可以对每个节点记录f[0/1][0/1][0/1][0/1/2]表示前/后缀,异或和为0/1,是否至少出现了两个1,出现了0/1/超过2个0。大力讨论即可。

      成功写了一晚上才不是因为要补十几面数学作业

    #include<iostream> 
    #include<cstdio>
    #include<cmath>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    #define ll long long
    #define N 100010
    char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')&&(c<'0'||c>'9')) c=getchar();return c;}
    int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
    int read()
    {
        int x=0,f=1;char c=getchar();
        while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
        while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
        return x*f;
    }
    int n,m,a[N];
    struct data{int f[2][2][2][3],l,r,sum;ll ans;
    }tree[N<<2];
    data merge(data x,data y)
    {
        data p;memset(p.f,0,sizeof(p.f));
        p.l=x.l,p.r=y.r;
        p.sum=x.sum+y.sum;
        p.ans=x.ans+y.ans;
        for (int i=0;i<2;i++)
        {
            int s1=0,s2=0;
            for (int j=0;j<2;j++)
                for (int k=0;k<3;k++)
                s1+=x.f[1][i][j][k],s2+=y.f[0][i][j][k];
            p.ans+=1ll*s1*s2;
        }
        for (int i=0;i<3;i++) 
            for (int j=2-i;j<3;j++)
                for (int u=0;u<2;u++)
                    for (int v=0;v<2;v++)
                    if (u|v) p.ans+=1ll*x.f[1][0][u][i]*y.f[0][1][v][j]+1ll*x.f[1][1][u][i]*y.f[0][0][v][j];
        int lone=x.sum,lzero=x.r-x.l+1-lone,rone=y.sum,rzero=y.r-y.l+1-rone;
        for (int i=0;i<2;i++) 
            for (int j=0;j<2;j++)
                for (int k=0;k<3;k++)
                p.f[0][i][j][k]+=x.f[0][i][j][k],p.f[0][i^(lone&1)][lone+i>=2||j][min(2,lzero+k)]+=y.f[0][i][j][k],
                p.f[1][i][j][k]+=y.f[1][i][j][k],p.f[1][i^(rone&1)][rone+i>=2||j][min(2,rzero+k)]+=x.f[1][i][j][k];
        return p;
    }
    void newpoint(int k,int x)
    {
        memset(tree[k].f,0,sizeof(tree[k].f));
        tree[k].f[0][x][0][x^1]=tree[k].f[1][x][0][x^1]=1;tree[k].ans=x^1;tree[k].sum=x;
    }
    void build(int k,int l,int r)
    {
        tree[k].l=l,tree[k].r=r;
        if (l==r){newpoint(k,a[l]);return;}
        int mid=l+r>>1;
        build(k<<1,l,mid);
        build(k<<1|1,mid+1,r);
        tree[k]=merge(tree[k<<1],tree[k<<1|1]);
    }
    void modify(int k,int p,int x)
    {
        if (tree[k].l==tree[k].r) {newpoint(k,x);return;}
        int mid=tree[k].l+tree[k].r>>1;
        if (p<=mid) modify(k<<1,p,x);
        else modify(k<<1|1,p,x);
        tree[k]=merge(tree[k<<1],tree[k<<1|1]);
    }
    data query(int k,int l,int r)
    {
        if (tree[k].l==l&&tree[k].r==r) return tree[k];
        int mid=tree[k].l+tree[k].r>>1;
        if (r<=mid) return query(k<<1,l,r);
        else if (l>mid) return query(k<<1|1,l,r);
        else return merge(query(k<<1,l,mid),query(k<<1|1,mid+1,r));
    }
    int main()
    {
    #ifndef ONLINE_JUDGE
        freopen("bzoj5294.in","r",stdin);
        freopen("bzoj5294.out","w",stdout);
        const char LL[]="%I64d
    ";
    #else
        const char LL[]="%lld
    ";
    #endif
        n=read();
        for (int i=1;i<=n;i++) a[i]=read();
        build(1,0,n);
        m=read();
        while (m--)
        {
            int op=read();
            if (op==1)
            {
                int x=read();
                modify(1,x,a[x]^=1);
            }
            else
            {
                int l=read(),r=read();
                printf(LL,query(1,l,r).ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    mock数据
    关于适配各种浏览器的图片预览。
    闭包
    兼容性 适配
    递归 使用callee
    webservice的model层命名空间不同的问题
    删除右键菜单中的Git
    windows server core 设置shell 及切换
    设置共享用户名密码
    Windows Remote Shell(WinRM)使用介绍
  • 原文地址:https://www.cnblogs.com/Gloid/p/10095788.html
Copyright © 2020-2023  润新知