首页 > 其他分享 >BZOJ4536 : 最大异或和II

BZOJ4536 : 最大异或和II

时间:2022-12-12 22:24:09浏览次数:36  
标签:flower const int BZOJ4536 st II 异或 Num return

建立$n+m$个点的无向图,其中$n$个点表示输入的数列,$m$个点表示答案的$m$个二进制位。

  • 对于输入的两个数$a[i],a[j]$,若它们存在公共二进制位,则可以通过同时选某一公共位来对答案贡献$0$,并完成两个数的选择,因此在数$i$和数$j$之间连边,边权为二维权值$(2,0)$。
  • 对于输入的某个数$a[i]$,若它二进制下第$j$位为$1$,则可以通过让它选这一位来对答案贡献$2^j$,因此在数$i$和位$j$之间连边,边权为二维权值$(1,2^j)$。

显然每个点最多只允许匹配一次,目标就是最大化二维权值的总和,即先保证$n$个数都完成了选择,再最大化每一位选择个数为奇数的贡献和。

利用一般图最大权匹配算法求出答案即可。

时间复杂度$O((n+m)^3)$。

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1023;
struct Num{
  int a;ll b;
  Num(){a=b=0;}
  Num(int _a,ll _b){a=_a;b=_b;}
  Num operator+(const Num&p)const{return Num(a+p.a,b+p.b);}
  Num operator-(const Num&p)const{return Num(a-p.a,b-p.b);}
  Num operator*(int p)const{return Num(a*p,b*p);}
  Num operator/(int p)const{return Num(a/p,b/p);}
  void operator+=(const Num&p){a+=p.a;b+=p.b;}
  void operator-=(const Num&p){a-=p.a;b-=p.b;}
  bool operator<(const Num&p)const{
    if(a!=p.a)return a<p.a;
    return b<p.b;
  }
  bool operator>(const Num&p)const{
    if(a!=p.a)return a>p.a;
    return b>p.b;
  }
  bool operator<=(const Num&p)const{
    if(a!=p.a)return a<p.a;
    return b<=p.b;
  }
  bool operator==(const Num&p)const{return a==p.a&&b==p.b;}
};
const Num INF(1e9,4e18),ZERO(0,0);
struct Edge{
  int u,v;Num w;
  Edge(){}
  Edge(int _u,int _v,const Num&_w){u=_u,v=_v,w=_w;}
}g[N][N];
int n,n_x,match[N],slack[N],st[N],pa[N],flower_from[N][N],S[N],vis[N];
Num lab[N];
vector<int> flower[N];
deque<int> q;
inline Num DIST(const Edge&e){return lab[e.u]+lab[e.v]-g[e.u][e.v].w*2;}
inline void update_slack(int u,int x){
  if(!slack[x]||DIST(g[u][x])<DIST(g[slack[x]][x]))slack[x]=u;
}
inline void set_slack(int x){
  slack[x]=0;
  for(int u=1; u<=n; ++u)
    if(g[u][x].w>ZERO&&st[u]!=x&&S[st[u]]==0)update_slack(u,x);
}
inline void q_push(int x){
  if(x<=n)return q.push_back(x);
  for(int i=0; i<flower[x].size(); i++)q_push(flower[x][i]);
}
inline void set_st(int x,int b){
  st[x]=b;
  if(x<=n)return;
  for(int i=0; i<flower[x].size(); ++i)set_st(flower[x][i],b);
}
inline int get_pr(int b,int xr){
  int pr=find(flower[b].begin(),flower[b].end(),xr)-flower[b].begin();
  if(pr%2==1){
    reverse(flower[b].begin()+1,flower[b].end());
    return (int)flower[b].size()-pr;
  }
  else return pr;
}
inline void set_match(int u,int v){
  match[u]=g[u][v].v;
  if(u<=n)return;
  Edge e=g[u][v];
  int xr=flower_from[u][e.u],pr=get_pr(u,xr);
  for(int i=0; i<pr; ++i)set_match(flower[u][i],flower[u][i^1]);
  set_match(xr,v);
  rotate(flower[u].begin(),flower[u].begin()+pr,flower[u].end());
}
inline void augment(int u,int v){
  int xnv=st[match[u]];
  set_match(u,v);
  if(!xnv)return;
  set_match(xnv,st[pa[xnv]]);
  augment(st[pa[xnv]],xnv);
}
inline int get_lca(int u,int v){
  static int t=0;
  for(++t; u||v; swap(u,v)){
    if(u==0)continue;
    if(vis[u]==t)return u;
    vis[u]=t;
    u=st[match[u]];
    if(u)u=st[pa[u]];
  }
  return 0;
}
inline void add_blossom(int u,int lca,int v){
  int b=n+1;
  while(b<=n_x&&st[b])++b;
  if(b>n_x)++n_x;
  lab[b]=ZERO;
  S[b]=0;
  match[b]=match[lca];
  flower[b].clear();
  flower[b].push_back(lca);
  for(int x=u,y; x!=lca; x=st[pa[y]])
    flower[b].push_back(x),flower[b].push_back(y=st[match[x]]),q_push(y);
  reverse(flower[b].begin()+1,flower[b].end());
  for(int x=v,y; x!=lca; x=st[pa[y]])
    flower[b].push_back(x),flower[b].push_back(y=st[match[x]]),q_push(y);
  set_st(b,b);
  for(int x=1; x<=n_x; ++x)g[b][x].w=g[x][b].w=ZERO;
  for(int x=1; x<=n; ++x)flower_from[b][x]=0;
  for(int i=0; i<flower[b].size(); ++i){
    int xs=flower[b][i];
    for(int x=1; x<=n_x; ++x)
      if(g[b][x].w==ZERO||DIST(g[xs][x])<DIST(g[b][x]))
        g[b][x]=g[xs][x],g[x][b]=g[x][xs];
    for(int x=1; x<=n; ++x)
      if(flower_from[xs][x])flower_from[b][x]=xs;
  }
  set_slack(b);
}
inline void expand_blossom(int b){
  for(int i=0; i<flower[b].size(); ++i)
    set_st(flower[b][i],flower[b][i]);
  int xr=flower_from[b][g[b][pa[b]].u],pr=get_pr(b,xr);
  for(int i=0; i<pr; i+=2){
    int xs=flower[b][i],xns=flower[b][i+1];
    pa[xs]=g[xns][xs].u;
    S[xs]=1,S[xns]=0;
    slack[xs]=0,set_slack(xns);
    q_push(xns);
  }
  S[xr]=1,pa[xr]=pa[b];
  for(int i=pr+1; i<flower[b].size(); ++i){
    int xs=flower[b][i];
    S[xs]=-1,set_slack(xs);
  }
  st[b]=0;
}
inline bool on_found_Edge(const Edge &e){
  int u=st[e.u],v=st[e.v];
  if(S[v]==-1){
    pa[v]=e.u,S[v]=1;
    int nu=st[match[v]];
    slack[v]=slack[nu]=0;
    S[nu]=0,q_push(nu);
  }
  else if(S[v]==0){
    int lca=get_lca(u,v);
    if(!lca)return augment(u,v),augment(v,u),1;
    else add_blossom(u,lca,v);
  }
  return 0;
}
inline void umin(Num&a,const Num&b){if(a>b)a=b;}
inline bool matching(){
  fill(S,S+n_x+1,-1),fill(slack,slack+n_x+1,0);
  q.clear();
  for(int x=1; x<=n_x; ++x)
    if(st[x]==x&&!match[x])pa[x]=0,S[x]=0,q_push(x);
  if(q.empty())return 0;
  for(;;){
    while(q.size()){
      int u=q.front();
      q.pop_front();
      if(S[st[u]]==1)continue;
      for(int v=1; v<=n; ++v)
        if(g[u][v].w>ZERO&&st[u]!=st[v]){
          if(DIST(g[u][v])==ZERO){
            if(on_found_Edge(g[u][v]))return 1;
          }
          else update_slack(u,st[v]);
        }
    }
    Num d=INF;
    for(int b=n+1; b<=n_x; ++b)
      if(st[b]==b&&S[b]==1)umin(d,lab[b]/2);
    for(int x=1; x<=n_x; ++x)
      if(st[x]==x&&slack[x]){
        if(S[x]==-1)umin(d,DIST(g[slack[x]][x]));
        else if(S[x]==0)umin(d,DIST(g[slack[x]][x])/2);
      }
    for(int u=1; u<=n; ++u){
      if(S[st[u]]==0){
        if(lab[u]<=d)return 0;
        lab[u]-=d;
      }
      else if(S[st[u]]==1)lab[u]+=d;
    }
    for(int b=n+1; b<=n_x; ++b)
      if(st[b]==b){
        if(S[st[b]]==0)lab[b]+=d*2;
        else if(S[st[b]]==1)lab[b]-=d*2;
      }
    q.clear();
    for(int x=1; x<=n_x; ++x)
      if(st[x]==x&&slack[x]&&st[slack[x]]!=x&&DIST(g[slack[x]][x])==ZERO)
        if(on_found_Edge(g[slack[x]][x]))return 1;
    for(int b=n+1; b<=n_x; ++b)
      if(st[b]==b&&S[b]==1&&lab[b]==ZERO)expand_blossom(b);
  }
  return 0;
}
inline pair<Num,int> weight_blossom(){
  fill(match,match+n+1,0);
  n_x=n;
  int n_matches=0;
  Num tot_weight=ZERO;
  for(int u=0; u<=n; ++u)st[u]=u,flower[u].clear();
  Num w_max=ZERO;
  for(int u=1; u<=n; ++u)
    for(int v=1; v<=n; ++v){
      flower_from[u][v]=(u==v?u:0);
      w_max=max(w_max,g[u][v].w);
    }
  for(int u=1; u<=n; ++u)lab[u]=w_max;
  while(matching())++n_matches;
  for(int u=1; u<=n; ++u)
    if(match[u]&&match[u]<u)
      tot_weight+=g[u][match[u]].w;
  return make_pair(tot_weight,n_matches);
}
ll a[N];
inline void add(int u,int v,const Num&w){g[u][v].w=g[v][u].w=w;}
int main(){
  int Case,_n,_m;
  scanf("%d",&Case);
  while(Case--){
    scanf("%d",&_n);
    _m=60;
    n=_n+_m;
    for(int u=1; u<=n; ++u)
      for(int v=1; v<=n; ++v)
        g[u][v]=Edge(u,v,ZERO);
    for(int i=1;i<=_n;i++)scanf("%lld",&a[i]);
    for(int i=1;i<=_n;i++){
      for(int j=0;j<_m;j++)if(a[i]>>j&1)add(i,_n+j+1,Num(1,1LL<<j));
      for(int j=1;j<i;j++)if(a[i]&a[j])add(i,j,Num(2,0));
    }
    pair<Num,int>ans=weight_blossom();
    printf("%lld\n",ans.first.b);
  }
  return 0;
}

  

标签:flower,const,int,BZOJ4536,st,II,异或,Num,return
From: https://www.cnblogs.com/clrs97/p/16977277.html

相关文章

  • python-miio 入门
    一、获取ip和tooken转载链接:https://github.com/PiotrMachowski/Xiaomi-cloud-tokens-extractor二、基础通信转载链接:https://github.com/rytilahti/python-miio/iss......
  • 剑指 Offer 56 - II. 数组中数字出现的次数 II(状态转移 位运算)
      ​​剑指Offer56-II.数组中数字出现的次数II​​难度中等38在一个数组 ​​nums​​ 中除一个数字只出现一次之外,其他数字都出现了三次。请找出那个只出现一次......
  • IIS 之 连接数、并发连接数、最大并发工作线程数、队列长度、最大工作进程数
    http://t.zoukankan.com/l1pe1-p-7742936.html一、IIS连接数一般购买过虚拟主机的朋友都熟悉购买时,会限制IIS连接数,顾名思义即为IIS服务器可以同时容纳客户请求的最......
  • IIS 6 下配置以 FastCGI 跑 PHP
    环境:操作系统:Windows2003ServerSP2PHP版本:php-5.2.6-Win321.下载FastCGIForIIS6http://www.iis.net/d...环境:操作系统:Windows200......
  • Nuxt.js IIS部署,Nuxt.js 发布部署vue-cli 安装 2020最新 vue 4.0安装
    第一步:服务器安装node.js环境1、安装node.js下载地址​​http://nodejs.cn/download/​​我是全部默认下一步的,安装成功之后运行命令查看是否安装成功如果没有出现版本号,......
  • 81. 搜索旋转排序数组 II
    已知存在一个按非降序排列的整数数组 nums ,数组中的值不必互不相同。在传递给函数之前,nums 在预先未知的某个下标 k(0<=k<nums.length)上进行了 旋转 ,使数组变为......
  • 力扣 leetcode 213. 打家劫舍 II
    问题描述你是一个专业的小偷,计划偷窃沿街的房屋,每间房内都藏有一定的现金。这个地方所有的房屋都围成一圈,这意味着第一个房屋和最后一个房屋是紧挨着的。同时,相邻的房屋......
  • 动态规划_打家劫舍III
    package数据结构和算法;publicclassd31_动态规划_打家劫舍III{publicstaticvoidmain(String[]args){//TODO自动生成的方法存根......
  • pgpool ii在lightdb下的性能测试
    1、从​​https://www.pgpool.net/​​下载最新版pgpoolii,如4.3.2。2、假设安装了postgresql或lightdb,百度一搜即可3、解压包,执行./configure &&make&&makeinstall4......
  • 59.螺旋矩阵II
    给定一个正整数 n,生成一个包含1到 n^2 所有元素,且元素按顺时针顺序螺旋排列的正方形矩阵。示例:输入:3输出:[[1,2,3],[8,9,4],[7,6,5]]力扣题......