zoukankan      html  css  js  c++  java
  • BZOJ4124 : [Baltic2015]Tug of war

    建立二分图,首先如果存在度数为$0$的点,那么显然无解。

    如果存在度数为$1$的点,那么这个点的匹配方案固定,可以通过拓扑排序去掉所有这种点。

    那么现在剩下的点度数都至少为$2$,因为左右点数相等,且左边每个点度数都是$2$,所以右边只能是每个点的度数都是$2$。

    在这种情况下每个连通块是一个环,相邻两条边不能同时选,一共有两种情况$x$和$y$。

    假设$xleq y$,那么把$x$加入$sum$,$y-x$既可以加入,又可以不加入,对$y-x$进行01背包即可。

    注意到本题中物品数不超过$2n$,物品价值之和不超过$2kleq 40n$。

    所以将01背包转化为多重背包后只有$O(sqrt{k})$种物品,二进制拆分+bitset优化即可。

    时间复杂度$O(frac{ksqrt{k}log k}{64})$。

    #include<cstdio>
    #include<bitset>
    #include<algorithm>
    using namespace std;
    const int N=120010,M=1200010;
    int n,m,K,i,j,k,x,y,z,g[N],v[N<<1],w[N<<1],nxt[N<<1],ed,d[N],h,t,q[N],vis[N],sum,cnt[M];
    bitset<M>f;
    inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
    inline void add(int x,int y,int z){
      d[x]++,d[y]++;
      v[++ed]=y;w[ed]=z;nxt[ed]=g[x];g[x]=ed;
      v[++ed]=x;w[ed]=z;nxt[ed]=g[y];g[y]=ed;
    }
    inline int go(int x){
      for(int i=g[x];i;i=nxt[i])if(!vis[v[i]])return v[i];
      return 0;
    }
    inline int get(int x,int y){for(int i=g[x];i;i=nxt[i])if(v[i]==y)return w[i];}
    int main(){
      read(n),read(K);m=n+n;
      for(i=1;i<=m;i++){
        read(x),read(y),read(z);
        add(i,x+m,z);
        add(i,y+n+m,-z);
      }
      m<<=1;
      for(i=1;i<=m;i++)if(!d[i])return puts("NO"),0;
      for(h=i=1;i<=m;i++)if(d[i]==1)q[++t]=i;
      while(h<=t){
        for(i=g[x=q[h++]];i;i=nxt[i])if(!vis[v[i]]){
          y=v[i];
          sum+=w[i];
          break;
        }
        vis[x]=vis[y]=1;
        for(i=g[y];i;i=nxt[i])if(!vis[x=v[i]]){
          if(!(--d[x]))return puts("NO"),0;
          if(d[x]==1)q[++t]=x;
        }
      }
      for(n=0,i=1;i<=m;i++)if(!vis[i]){
        vis[q[t=1]=i]=1;
        for(j=go(i);j;j=go(j))vis[q[++t]=j]=1;
        q[t+1]=q[1];
        x=y=0;
        for(j=1;j<=t;j+=2)x+=get(q[j],q[j+1]);
        for(j=2;j<=t;j+=2)y+=get(q[j],q[j+1]);
        if(x>y)swap(x,y);
        sum+=x;
        cnt[y-x]++;
        n=max(n,y-x);
      }
      for(f[0]=i=1;i<=n;i++)for(j=1;cnt[i];j<<=1){
        k=min(cnt[i],j);
        cnt[i]-=k;
        f|=f<<(i*k);
      }
      for(i=-K;i<=K;i++)if(i-sum>=0&&i-sum<M)if(f[i-sum])return puts("YES"),0;
      return puts("NO"),0;
    }
    

      

  • 相关阅读:
    Locale IDs Assigned by Microsoft (zz)
    MFC 版本
    vs macro shortcuts
    关于strassen矩阵乘法的矩阵大小不是2^k的形式时,时间复杂度是否还是比朴素算法好的看法
    团体程序设计天梯赛 L2-016. 愿天下有情人都是失散多年的兄妹
    团体程序设计天梯赛-练习集 L1-031. 到底是不是太胖了
    团体程序设计天梯赛 L3-004. 肿瘤诊断
    团体程序设计天梯赛 L2-006. 树的遍历 L2-011. 玩转二叉树
    团体程序设计天梯赛 L1-011. A-B
    团体程序设计天梯赛 L1-010. 比较大小
  • 原文地址:https://www.cnblogs.com/clrs97/p/6347610.html
Copyright © 2011-2022 走看看