zoukankan      html  css  js  c++  java
  • BZOJ4644 : 经典傻逼题

    设每个点的权值为和它相连的所有边的权值的异或和,那么等价于选若干个点,使得点权异或和最大,这显然只需要维护一组线性基,然后从高位到低位贪心选取即可。

    对于本题,因为有修改操作,所以考虑按时间分治,并用bitset加速,时间复杂度$O(frac{mlog mL^2}{64})$。

    针对插入操作,可以用Four Russian Method进一步优化。

    将$1000$个基$4$个一组分成$250$组,每组对于$2^4$种可能的插入向量预处理出消元后的结果。

    那么插入只需要$250$次消元,插入之后重新预处理那块即可。

    时间复杂度$O(frac{mlog mL^2}{64log L})$。

    #include<cstdio>
    #include<cstring>
    #include<bitset>
    #include<vector>
    #define N 505
    using namespace std;
    typedef bitset<1000>bs;
    int n,m,i,x,y,cnt,vis[N],cur,idb[N],idg[N];
    bs B[1000],fin,w,a[N],q[2010],pb[N];
    struct P{int l,r,p;P(int _l,int _r,int _p){l=_l,r=_r,p=_p;}};
    vector<P>V;
    struct Block{
      bs a[16];int b[16];
      void build(int x){
        for(int S=1;S<16;S++){
          int j;
          for(j=3;~j;j--)if(S>>j&1)break;
          if(B[x+3-j][x+3-j]){
            a[S]=B[x+3-j];
            int ret=S;
            for(int i=j;~i;i--)if(B[x+3-j][x+3-i])ret^=1<<i;
            if(ret)a[S]^=a[ret],b[S]=b[ret];else b[S]=0;
          }else a[S].reset(),b[S]=1<<j;
        }
      }
    }G[250],pg[N];
    inline void ins(bs x){
      int i,j,k;
      for(i=j=0;i<250;i++){
        int S=0;
        for(k=0;k<4;j++,k++){
          S<<=1;
          if(x[j])S++;
        }
        if(!S)continue;
        x^=G[i].a[S];
        if(G[i].b[S]){
          int k=j-1-__builtin_ctz(G[i].b[S]);
          cur++;
          idb[cur]=k;
          idg[cur]=i;
          pb[cur]=B[k];
          pg[cur]=G[i];
          B[k]=x;
          G[i].build(j-4);
          break;
        }
      }
    }
    inline void get(){
      static char s[1010];
      scanf("%s",s);
      w.reset();
      int n=strlen(s);
      for(int i=0;i<n;i++)if(s[i]=='1')w[1000+i-n]=1;
    }
    inline void retrace(int x){
      while(cur>x){
        B[idb[cur]]=pb[cur];
        G[idg[cur]]=pg[cur];
        cur--;
      }
    }
    void solve(int l,int r,vector<P>V){
      int t=cur;
      vector<P>S;
      for(vector<P>::iterator it=V.begin();it!=V.end();it++)
        if(it->l<=l&&r<=it->r)ins(q[it->p]);
        else S.push_back(*it);
      if(l==r){
        fin.reset();
        for(int i=0;i<1000;i++)if(!fin[i])if(B[i][i])fin^=B[i];
        bool flag=0;
        for(int i=0;i<1000;i++)if(fin[i])putchar('1'),flag=1;else if(flag)putchar('0');
        if(!flag)putchar('0');
        puts("");
        retrace(t);
        return;
      }
      int mid=(l+r)>>1;
      solve(l,mid,S),solve(mid+1,r,S);
      retrace(t);
    }
    int main(){
      scanf("%d",&n);
      scanf("%d%d",&n,&m);
      for(i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        get();
        x--,y--;
        if(vis[x])q[++cnt]=a[x],V.push_back(P(vis[x],i-1,cnt));
        if(vis[y])q[++cnt]=a[y],V.push_back(P(vis[y],i-1,cnt));
        vis[x]=vis[y]=i;
        a[x]^=w,a[y]^=w;
      }
      for(i=0;i<n;i++)if(vis[i])q[++cnt]=a[i],V.push_back(P(vis[i],m,cnt));
      for(i=0;i<250;i++)G[i].build(i<<2);
      solve(1,m,V);
      return 0;
    }
    

      

  • 相关阅读:
    10.用户管理
    9.更新系统时间
    8.标准输入输出重定向
    7.文件压缩与find命令
    6.Linux文件的详细属性
    5.Linux基础命令
    4.Linux目录结构
    3.磁盘光驱挂载
    2.xshell连接
    javascript中的location的用法
  • 原文地址:https://www.cnblogs.com/clrs97/p/5734792.html
Copyright © 2011-2022 走看看