gmoj 7067. 【2021.4.24NOI模拟】对称线性规划问题

这道题需要很大的脑洞。

首先答案显然可以转化为两类点和的差最小。

我们可以大胆猜想,两类点和的差为 0 。

因为是 1 ~ 4n 的全排列,所以总和为 \(2n*(4n+1)\) ,每一类点有 \(2n\) 个,他们有一个 \(2n\) 的因数,所以想到把数字配凑为两两和为 \(4n+1\) 的形式,也就是 1 和 4n 配,2 和 4n-1 配,3 和 4n-2 配。

那么如果相配的点颜色相等,那么两类点和的差显然为 0 。考虑把每一组的四个数看作一个点,相配的两个数字各自所在的点连一条边,显然每个点度数为4 ( 自环就把度数加二 ),那么首先一定存在欧拉回路,构造方法就是把欧拉回路上序号为奇数的边所代表的两个数字染成同种颜色。

证明很明显,题目限制要求保留同一种颜色的边后,每个点的度数为二,那么分成每个点没有自环,有一个自环,有两个自环三种情况,只剩下欧拉回路奇数边后,显然度数都是二。

贴上代码

#include<cstdio>
using namespace std;

const int N=4e6+10;
struct zy{int to,ne,x,y;}e[N];
int b[N],w[N],s[N],bz[N],a[N];
int n,m,i,j,x,y,l,la;

inline int read(){
	int x=0; char c=getchar();
	while(c<'0'||c>'9') c=getchar();
	while('0'<=c&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x;
}
inline int P(int x){return (x-1)/4+1;}
inline void ad(int x,int y,int p,int q){
	e[++l]=(zy){y,w[x],p,q}; w[x]=l;
	e[++l]=(zy){x,w[y],p,q}; w[y]=l;
	if (x==y) s[x]++;
}
inline void dfs(int x,int la){
	b[x]=0;
	for(int i=w[x];i;i=e[i].ne)
		if (!bz[i]){
			bz[i]=bz[i^1]=1;
			dfs(e[i].to,i);
		}
	l++;
	if (l&1) a[e[la].x]=a[e[la].y]=1;
}
int main(){
	freopen("slp.in","r",stdin);
	freopen("slp.out","w",stdout);
	n=read(); m=4*n+1; l=1;
	for(i=1;i<=n*4;++i){
		x=read();
		b[x]=i; y=m-x;
		if (b[y]) ad(P(b[x]),P(b[y]),b[x],b[y]);
	}
	for(i=1;i<=n;++i){
		if (b[i]){
			if (s[i]==2){
				a[e[w[i]].x]=a[e[w[i]].y]=1;
				b[i]=0; continue;
			}
			l=0; dfs(i,0);
		}
	}
	for(i=1;i<=4*n;++i)
		printf("%d ",a[i]);
	return 0;
}
上一篇:20210616总结


下一篇:【译】N 皇后问题 – 构造法原理与证明 时间复杂度O(1)