题意:$2n$个位置排成一列,有一些位置已经填了数字($0\cdots n-1$中每个数字出现$0$次或$2$次),问是否存在一种填数方案使得用$n$个不相交的半圆可以把相同的数字连起来

首先把所有已经填了的数字的半圆画出来,如果两个半圆相交那么它们必须在异侧,在相交的半圆之间连边,如果不是二分图那么就无解

我们用$-1$代表未填数的位置,给$-1$的位置分配$1$代表这个位置向上连线,$0$代表这个位置向下连线

朴素的想法是:对于每个半圆$[l,r]$,枚举它在上方还是在下方,如果在上方,那么$[l,r]$中必须有偶数个$1$,如果在下方,那么$[l,r]$中必须有偶数个$0$(用$-1$的个数减去$0$的个数即可得到$1$的个数),并且因为对于每个不是$-1$的位置$i$,因为不能给它分配$1$,所以$[i,i]$中必须有偶数个$0$,最后,显然所有位置上必须有偶数个$1$

现在问题变为:给定一些区间$[l,r]$和对其中$1$的个数的奇偶性要求,问是否能满足,求异或前缀和后就变成对一些变量的异或值限制,直接dfs一遍看是否冲突即可

但是这样会很慢,考虑优化

如果一个半圆$[l,r]$不与其他半圆相交,当区间长度为偶数时,它放在上或下都要求区间中$1$的个数是偶数,当区间长度为奇数时,放在上或下可以使得区间中$1$的个数是奇数或是偶数,又因为它和其他半圆互不影响,所以我们这样处理:如果区间长度为奇数,不管它,如果区间长度为偶数,那么我们不用枚举它放在上还是下,直接令区间中$1$的个数是偶数即可

所以我们只用对二分图中大小$\geq2$的连通块枚举它的两半分别在上还是下,因为最多有$\frac n2$个半圆,所以最多有$\frac n4$个大小$\geq2$的连通块,所以总时间复杂度为$O(n2^{\frac n4})$

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
struct seg{
	int l,r;
	seg(int a=0,int b=0){l=a;r=b;}
}e[30];
bool ints(seg a,seg b){
	if(a.l>b.l)swap(a,b);
	return b.l<a.r&&b.r>a.r;
}
vector<int>vt[30][2];
vector<int>sg;
int cnt;
struct graph{
	int h[30],nex[610],to[610],M,n;
	void reset(){
		M=0;
		memset(h,0,sizeof(h));
	}
	void ins(int a,int b){
		M++;
		to[M]=b;
		nex[M]=h[a];
		h[a]=M;
	}
	void add(int a,int b){
		ins(a,b);
		ins(b,a);
	}
	int c[30];
	bool dfs(int x,int f){
		if(~c[x])return c[x]==f;
		vt[cnt][f].push_back(x);
		c[x]=f;
		for(int i=h[x];i;i=nex[i]){
			if(!dfs(to[i],f^1))return 0;
		}
		return 1;
	}
	bool gao(int n){
		sg.clear();
		memset(c,-1,sizeof(c));
		cnt=0;
		for(int i=1;i<=n;i++){
			if(c[i]==-1){
				if(h[i]){
					vt[cnt][0].clear();
					vt[cnt][1].clear();
					if(!dfs(i,0))return 0;
					cnt++;
				}else
					sg.push_back(i);
			}
		}
		return 1;
	}
}g;
struct graph2{
	int h[60],nex[210],to[210],v[210],M;
	void reset(){
		M=0;
		memset(h,0,sizeof(h));
	}
	void ins(int a,int b,int c){
		M++;
		to[M]=b;
		v[M]=c;
		nex[M]=h[a];
		h[a]=M;
	}
	void add(int a,int b,int c){
		ins(a,b,c);
		ins(b,a,c);
	}
	int c[60];
	bool dfs(int x,int f){
		if(~c[x])return c[x]==f;
		c[x]=f;
		for(int i=h[x];i;i=nex[i]){
			if(!dfs(to[i],f^v[i]))return 0;
		}
		return 1;
	}
	bool gao(int n){
		memset(c,-1,sizeof(c));
		for(int i=0;i<=n;i++){
			if(c[i]==-1&&!dfs(i,0))return 0;
		}
		return 1;
	}
}g2;
int a[60],s[60];
class DisjointSemicircles{
	public:
		string getPossibility(vector<int>v){
			int n,i,j,M;
			n=v.size();
			M=0;
			for(i=1;i<=n;i++){
				a[i]=v[i-1];
				s[i]=s[i-1]+(a[i]==-1);
				if(~a[i]){
					for(j=1;j<i;j++){
						if(a[j]==a[i])break;
					}
					if(i!=j)e[++M]=seg(j,i);
				}
			}
			g.reset();
			for(i=1;i<M;i++){
				for(j=i+1;j<=M;j++){
					if(ints(e[i],e[j]))g.add(i,j);
				}
			}
			if(!g.gao(M))return"IMPOSSIBLE";
			for(i=0;i<1<<cnt;i++){
				g2.reset();
				for(int x:sg){
					if((e[x].r-e[x].l)&1)g2.add(e[x].l-1,e[x].r,0);
				}
				for(j=0;j<cnt;j++){
					for(int x:vt[j][i>>j&1])g2.add(e[x].l-1,e[x].r,0);
					for(int x:vt[j][~i>>j&1])g2.add(e[x].l-1,e[x].r,(s[e[x].r]-s[e[x].l-1])&1);
				}
				for(j=1;j<=n;j++){
					if(~a[j])g2.add(j-1,j,0);
				}
				g2.add(0,n,0);
				if(g2.gao(n))return"POSSIBLE";
			}
			return"IMPOSSIBLE";
		}
};
/*
int main(){
	int x;
	DisjointSemicircles cl;
	vector<int>v;
	for(scanf("%d",&x);x!=-2;scanf("%d",&x))v.push_back(x);
	puts(cl.getPossibility(v).c_str());
}
*/

[SRM568]DisjointSemicircles的更多相关文章

  1. Topcoder口胡记 SRM 562 Div 1 ~ SRM 599 Div 1

    据说做TC题有助于提高知识水平? :) 传送门:https://284914869.github.io/AEoj/index.html 转载请注明链接:http://www.cnblogs.com/B ...

  2. TC做题笔记

    SRM593 Div1Medium--May The Best Pet Win(bitset优化) Description 给出n个元素取值的max.min,把这n个元素分割成两个集合,求如何分割使两 ...

随机推荐

  1. oracle scott用户不存在

    scott用户拥有一些基础的数据表,可以供我们练习sql.先执行 alter user scott account unlock; 查看scott用户是否存在 当scott用户不存在,我们就需要在$O ...

  2. poj 2104 可持久化线段树

    我们先离散化,然后根据权值建立线段树,假设我们现在有一颗权值线段树,表示在区间1-n中每个数出现了几次,那么我们可以二分的求出来这个区间的k大值,类似sbt的select操作,那么因为点的权值插入是无 ...

  3. linux下进行base64编码解码

    1.编码 2.解码

  4. linux percpu机制解析【转】

    转自:http://blog.csdn.net/wh8_2011/article/details/53138377 一.概述 每cpu变量是最简单也是最重要的同步技术.每cpu变量主要是数据结构数组, ...

  5. rdpClient

    https://github.com/jean343/RPI-GPU-rdpClient https://github.com/Nullstr1ng/MultiRDPClient.NET https: ...

  6. 判断ArcSDE是否安装成功

    安装SDE后在ArcMap的Toolboxes - Data Management Tools中会新增Geodatabase Administration 即数据管理工具下面会新增地理数据库管理

  7. 【Android开发日记】之基础篇(二)——Android的动画效果

          什么是动画,动画的本质是通过连续不断地显示若干图像来产生“动”起来的效果.比如说一个移动的动画,就是在一定的时间段内,以恰当的速率(起码要12帧/秒以上,才会让人产生动起来的错觉)每隔若干 ...

  8. Python3发送qq邮件,测试通过

    import smtplib from email.mime.text import MIMEText # 收件人列表 mail_namelist = ["10402852@qq.com&q ...

  9. qtp录制时间控件不允许用户手动输入的解决办法

    qtp录制时间控件不允许用户手动输入的解决办法 [前面的话] 一边学习qtp,一边用自己的项目试着写代码,而遇到一个问题就会让自己卡壳很久,这次也是这样的,在写好了登录代码以后,自己就试着写第一个预订 ...

  10. Ljava/lang/Iterable与AbstractMethodError

    java.lang.AbstractMethodError: com.example.demo.repository.UserRepositoryImpl.findAll()Ljava/lang/It ...