列表

详情


NC205429. 配对

描述

一个大小为n的数组(数字可能重复),现在要求你选择出若干对数字满足条件:
1. 假设选出的数字是x,y,要求x+y为奇数。
2. 一个数字要么不选,要么只能出现在一个对中,不允许一个数字出现在多个对中。
3. 数字之间的不同指的是数字在原数组中的下标不同。
一对数字的价值为:x^y。^表示异或运算。

现在要求你在满足选择出最大对数的情况下,使得所有这些数字对的价值之和最大。

输入描述

第一行输入数组大小n,保证n<=600。
第二行输入n个数字,表示输入的数组。保证输入的数字为正整数,且<=

输出描述

在一行输出两个数字x,y表示最大对数,价值之和,数字之间用空格分隔。

示例1

输入:

4
1 2 3 4

输出:

2 10

说明:

(1^2)+(3^4)=10

原站题解

上次编辑到这里,代码来自缓存 点击恢复默认模板

C++11(clang++ 3.9) 解法, 执行用时: 815ms, 内存消耗: 3532K, 提交时间: 2020-05-24 16:47:49

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=611;
const ll inf=1e16+7;
struct Side{
	int v,ne,w,val;
	Side(){}
	Side(int v,int val):v(v),val(val){}
	bool operator<(const Side &s1)const{
		return val>s1.val;
	}
}S[N*N];
bool vis[N];
int sb,se,sn,a[N],head[N],lu[N],h[N];
ll dis[N],flow[N];
void init(int n){
	sn=0;
	for(int i=0;i<=n;i++) head[i]=-1;
}
void add(int u,int v,int w,int val){
	S[sn].w=w;S[sn].val=val;
	S[sn].v=v;S[sn].ne=head[u];
	head[u]=sn++;
}
void addE(int u,int v,int w,int val){
	add(u,v,w,val);add(v,u,0,-val); 
}
bool dijk(int n){
	priority_queue<Side> q;
	for(int i=0;i<=n;i++){
		lu[i]=-1;	
		dis[i]=flow[i]=inf;
	}
	dis[sb]=0;
	q.push(Side(sb,dis[sb]));
	while(!q.empty()){
		int u=q.top().v,w=q.top().val;q.pop();
		if(dis[u]<w) continue;
		for(int i=head[u];~i;i=S[i].ne){
			int v=S[i].v;
			if(S[i].w>0&&dis[v]>dis[u]+S[i].val+h[u]-h[v]){
				lu[v]=i;
				dis[v]=dis[u]+S[i].val+h[u]-h[v];
				flow[v]=min(flow[u],1ll*S[i].w);
				q.push(Side(v,dis[v]));
			}
		}
	}
	return dis[se]!=inf; 
}
int mfml(int n){
	int ans=0;
	ll ansc=0;
	for(int i=0;i<=n;i++) h[i]=0;
	while(dijk(n)){
		ans+=flow[se];
		ansc+=flow[se]*(dis[se]+h[se]-h[sb]);
		for(int i=lu[se];~i;i=lu[S[i^1].v]){
			S[i].w-=flow[se];
			S[i^1].w+=flow[se];
		}
		for(int i=0;i<=n;i++) h[i]+=dis[i];
	}
	printf("%d %lld\n",ans,-ansc); 
	return 0;
}
int main(){
	int n;
	scanf("%d",&n);
	sb=0;se=n+1;
	init(n+1);
	for(int i=1;i<=n;i++){
		scanf("%lld",&a[i]);
		if(a[i]&1) addE(sb,i,1,0);
		else addE(i,se,1,0);
		for(int j=1;j<i;j++){
			if((a[i]+a[j])&1){
				if(a[i]&1) addE(i,j,1,-(a[i]^a[j]));
				else addE(j,i,1,-(a[i]^a[j]));
			}
		}
	}
	mfml(n+1);
	return 0;
}

C++14(g++5.4) 解法, 执行用时: 4456ms, 内存消耗: 7516K, 提交时间: 2020-05-24 16:42:07

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<b;i++)
#define mem(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const ll maxn=600*600+9,maxv=600*600+9;
struct Edge { int to,cap,cost,nex; };
vector<Edge> G;
int head[maxn],pre[maxn],maxflow=0;
ll mincost=0;
void addedge(int f,int t,int cap,int cost) {
	G.push_back({t,cap,cost,head[f]});
	head[f]=G.size()-1;
	G.push_back({f,0,-cost,head[t]});
	head[t]=G.size()-1;
}
int spfa(int s,int t) {
	queue<int> q;
	static int dis[maxn];
	static bool used[maxn]={};
	memset(dis,0x3f,sizeof(dis));
	memset(pre,0xff,sizeof(pre));
	dis[s]=0;used[s]=1;q.push(s);
	while (!q.empty()) {
		int u=q.front();q.pop();used[u]=0;
		for (int i=head[u];i!=-1;i=G[i].nex) {
			int v=G[i].to;
			if (G[i].cap&&dis[v]>dis[u]+G[i].cost) {
				dis[v]=dis[u]+G[i].cost;
				pre[v]=i;
				if (used[v]==0) q.push(v),used[v]=1;
			}
		}
	}
	return pre[t]!=-1;
}
void MCMF(int s,int t) {
	while (spfa(s,t)) {
		int f=INT_MAX;
		for (int i=pre[t];i!=-1;i=pre[G[i^1].to])
			f=min(f,G[i].cap);
		maxflow+=f;
		for (int i=pre[t];i!=-1;i=pre[G[i^1].to]) {
			G[i].cap-=f;
			G[i^1].cap+=f;
			mincost+=(ll)f*(ll)G[i].cost;
		}
	}
}
vector<int> odd,even;
int a[609]={};
int main() {
	memset(head,-1,sizeof head);
	int n;cin>>n;
	rep(i,1,n+1) {
		scanf("%d",a+i);
		if (a[i]&1) odd.push_back(i);
		else even.push_back(i);
	}
	int s=602,t=603;
	printf("%d ",min(odd.size(),even.size()));
	for (int i:odd) addedge(s,i,1,0);
	for (int i:even) addedge(i,t,1,0);
	for (int i:odd) for (int j:even) addedge(i,j,1,-(a[i]^a[j]));
	MCMF(s,t);
	printf("%lld",-mincost);
}

上一题