题面
题意:一个图,边权为两个端点的异或值,有的点权已经确定
求总边权最小,及在此条件下点权和最小
异或每位分开考虑,就变成了每个点选0或1的二选一问题
最小割能解决的问题:
①选0,选1有代价
②某两个选不一样的有代价
③某几个选一样的有收益
则本题要求的是在②最小的情况下①最小
则把②的代价带上n+1的权即可
#include <iostream>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <ctime>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
#define mmst(a, b) memset(a, b, sizeof(a))
#define mmcp(a, b) memcpy(a, b, sizeof(b))
typedef long long LL;
const int N=1020,T=501,M=200200,oo=1e7;
int n,m,a[N],u[M],v[M];
int cnt,head[N],nex[M],to[M],cap[M];
int q[N],lter[N],level[N];
LL ans1,ans2;
void add(int u,int v,int w,int rw)
{
to[cnt]=v;
cap[cnt]=w;
nex[cnt]=head[u];
head[u]=cnt++;
to[cnt]=u;
cap[cnt]=rw;
nex[cnt]=head[v];
head[v]=cnt++;
}
bool bfs()
{
mmcp(lter,head);
mmst(level,-1);
level[0]=1;
int hh=1,tt=1;
q[1]=0;
while(hh<=tt)
{
int hy=q[hh++];
for(int h=head[hy];h;h=nex[h])
if(level[to[h]]<0&&cap[h])
{
q[++tt]=to[h];
level[to[h]]=level[hy]+1;
}
}
return level[T]>0;
}
int dfs(int v,int f)
{
if(!f||v==T)
return f;
int ret=0;
for(int &h=lter[v];h;h=nex[h])
if(cap[h]&&level[to[h]]>level[v])
{
int d=dfs(to[h],min(f,cap[h]));
f-=d;
ret+=d;
cap[h]-=d;
cap[h^1]+=d;
if(!f)
break;
}
return ret;
}
int main()
{
cin>>n>>m;
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
if(a[i]>0)
ans2+=a[i];
}
for(int i=1;i<=m;i++)
scanf("%d%d",&u[i],&v[i]);
for(int ii=0;ii<=29;ii++)
{
mmst(head,0);
cnt=2;
for(int i=1;i<=n;i++)
if(a[i]>=0)
{
if(a[i]&(1<<ii))
add(i,T,oo,0);
else
add(0,i,oo,0);
}
else
add(0,i,1,0);
for(int i=1;i<=m;i++)
add(u[i],v[i],n+1,n+1);
int flow=0;
while(bfs())
flow+=dfs(0,oo);
ans1+=(1ll<<ii)*(LL)(flow/(n+1));
ans2+=(1ll<<ii)*(LL)(flow%(n+1));
}
cout<<ans1<<endl<<ans2<<endl;
return 0;
}