CF1572D
将每个人视为一个节点,可以一组的人连边
对于连边的两个人,他们的二进制中1的个数差为1,奇偶不同
所以这个图构成一个二分图,转化为二分图最大权匹配
而注意到,每选择一条边,有最多 \(2n-2\)条边不能选了,因此我们只需要保留边权最大的 \(2nk\) 条边即可
然后跑一个费用流即可
#include<bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define pb push_back
int count(int st){
int sum=0;
while(st)sum+=st&1,st>>=1;
return sum;
}
int n,k,a[(1<<20)+5];
struct edge{
int v,w,cst,nx;
}e[50005];
int cnt=1,hd[(1<<20)+15];
void add(int u,int v,int w,int c){
e[++cnt]=edge{v,w,c,hd[u]};
hd[u]=cnt;
}
void add_edge(int u,int v,int w,int c){
// printf("%d %d %d %d\n",u,v,w,c);
add(u,v,w,c);
add(v,u,0,-c);
}
int s,t,tot;
priority_queue<pair<int,pii>,vector<pair<int,pii>>,greater<pair<int,pii>>> pq;
vector<int> nec;
int vst[(1<<20)+15];
int flow[(1<<20)+15],dist[(1<<20)+15],pre[(1<<20)+15];
bool vis[(1<<20)+15];
bool spfa(){
for(int i:nec)dist[i]=0x3f3f3f3f,flow[i]=0,pre[i]=0;
queue<int> q;q.push(s);vis[s]=1;
flow[s]=0x3f3f3f3f;dist[s]=0;
while(!q.empty()){
int u=q.front();q.pop();
vis[u]=0;
for(int i=hd[u];i;i=e[i].nx){
int v=e[i].v;
if(dist[v]<=dist[u]+e[i].cst || e[i].w<=0)continue;
dist[v]=dist[u]+e[i].cst;
flow[v]=min(flow[u],e[i].w);
pre[v]=i;
if(!vis[v])q.push(v),vis[v]=1;
}
}
return dist[t]!=0x3f3f3f3f;
}
int solve(){
int res=0;
while(spfa()){
res+=flow[t]*dist[t];
int u=t;
while(u!=s){
int id=pre[u];
e[id].w-=flow[t];e[id^1].w+=flow[t];
u=e[id^1].v;
}
}
return res;
}
int main(){
scanf("%d%d",&n,&k);
for(int i=0;i<(1<<n);i++)scanf("%d",&a[i]);
for(int i=0;i<(1<<n);i++)
for(int j=0;j<n;j++)
if(i<(i^(1<<j))){
pq.push(mp(a[i]+a[i^(1<<j)],mp(i,i^(1<<j))));
tot++;
if(tot>2*n*k)pq.pop(),tot--;
}
while(!pq.empty()){
int u=pq.top().se.fi,v=pq.top().se.se,w=pq.top().fi;pq.pop();
if(count(u)%2==1)swap(u,v);
add_edge(u,v,1,-w);
vst[u]=1;vst[v]=2;
}
s=(1<<20);t=(1<<20)+1;
for(int i=0;i<(1<<n);i++)
if(vst[i]==1)add_edge(t+1,i,1,0),nec.pb(i);
else if(vst[i]==2)add_edge(i,t+2,1,0),nec.pb(i);
add_edge(s,t+1,k,0);
add_edge(t+2,t,k,0);
nec.pb(s);nec.pb(t);
nec.pb(t+1);nec.pb(t+2);
printf("%d\n",-solve());
return 0;
}
浙公网安备 33010602011771号