zoukankan      html  css  js  c++  java
  • [BZOJ4945][NOI2017]游戏

    bzoj
    luogu

    sol

    先考虑(d=0)怎么做吧。

    每个位置上只有两种选法,相当于每个位置是一个布尔变量,选第一种方案布尔值为0,选第二种方案布尔值为1。

    然后考虑一组限制条件((i,h_i,j,h_j)),设(u)表示([)(i)位置上选(h_i])(v)表示([)(j)位置上选(h_j])

    可以分三种情况讨论:

    1、如果在(i)位置上填(h_i)不合法,那这个限制条件就是没用的。直接忽略。
    2、如果在(i)位置上填(h_i)合法而在(j)位置上填(h_j)不合法,那么就不能在(i)位置上填(h_i)。连边(u o u')
    3、如果在两个位置上填均合法,那么就连边(u o v)注意!2-SAT问题在连边时要同时对逆否命题连边!所以还要连一条(v' o u')

    然后跑(2-SAT),跑完以后:

    1、判断合法性:检查(i)(i')是否在同一个强连通分量中。

    2、输出方案:由于缩强连通分量后图变成了一个(DAG),同时一个条件可以推得其后继的所有条件,所以一定是优先选拓扑序靠后的。鉴于在(Tarjan)中强连通分量从后往前标号,所以只要选择标号较小的条件就好了。

    这样子对于(d=0)的部分就可以直接(O(n+m))解决了。

    那么(d>0)
    发现(dle8),感觉可以暴搜?复杂度(O(3^d(n+m)))

    发现我们枚举的其实是不能选哪个,所以其实只要对每个(x)位置枚举两个就可以了。

    复杂度(O(2^d(n+m)))

    code

    在uoj上被hack了。。。

    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int gi()
    {
    	int x=0,w=1;char ch=getchar();
    	while ((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
    	if (ch=='-') w=0,ch=getchar();
    	while (ch>='0'&&ch<='9') x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
    	return w?x:-x;
    }
    const int N = 2e5+5;
    int n,d,pos[9],m,p1[N],c1[N],p2[N],c2[N];
    char s[N];
    int to[N],nxt[N],head[N],cnt,dfn[N],low[N],tim,Stack[N],top,vis[N],bel[N],scc;
    void link(int u,int v){to[++cnt]=v;nxt[cnt]=head[u];head[u]=cnt;}
    void Tarjan(int u)
    {
    	dfn[u]=low[u]=++tim;
    	Stack[++top]=u;vis[u]=1;
    	for (int e=head[u];e;e=nxt[e])
    		if (!dfn[to[e]]) Tarjan(to[e]),low[u]=min(low[u],low[to[e]]);
    		else if (vis[to[e]]) low[u]=min(low[u],dfn[to[e]]);
    	if (dfn[u]==low[u])
    	{
    		++scc;int v;
    		do{
    			v=Stack[top--];
    			vis[v]=0;bel[v]=scc;
    		}while (u!=v);
    	}
    }
    void work()
    {
    	memset(head,0,sizeof(head));cnt=0;
    	for (int i=1;i<=m;++i)
    	{
    		int u=(c1[i]-s[p1[i]]+3)%3;
    		int v=(c2[i]-s[p2[i]]+3)%3;
    		if (u)
    			if (v)
    			{
    				u>>=1;v>>=1;
    				link(p1[i]+u*n,p2[i]+v*n);
    				link(p2[i]+(v^1)*n,p1[i]+(u^1)*n);
    			}
    			else
    			{
    				u>>=1;
    				link(p1[i]+u*n,p1[i]+(u^1)*n);
    			}
    	}
    	memset(dfn,0,sizeof(dfn));tim=scc=0;
    	for (int i=1;i<=2*n;++i) if (!dfn[i]) Tarjan(i);
    	for (int i=1;i<=n;++i) if (bel[i]==bel[i+n]) return;
    	for (int i=1;i<=n;++i)
    		if (bel[i]<bel[i+n]) putchar((s[i]+1)%3+'A');
    		else putchar((s[i]+2)%3+'A');
    	puts("");exit(0);
    }
    void dfs(int i)
    {
    	if (i==d+1) {work();return;}
    	s[pos[i]]=0;dfs(i+1);
    	s[pos[i]]=1;dfs(i+1);
    }
    int main()
    {
    	n=gi();gi();scanf("%s",s+1);
    	for (int i=1;i<=n;++i)
    		if (s[i]=='x') pos[++d]=i;
    		else s[i]-='a';
    	m=gi();
    	for (int i=1;i<=m;++i)
    		p1[i]=gi(),c1[i]=getchar()-'A',p2[i]=gi(),c2[i]=getchar()-'A';
    	dfs(1);
    	return puts("-1"),0;
    }
    
  • 相关阅读:
    POJ 3468 A Simple Problem with Integers(线段树 区间更新)
    Windows Mobile 6.0 SDK和中文模拟器下载
    Linux学习笔记——例说makefile 头文件查找路径
    uva 11427
    腾讯2014年实习生招聘笔试面试经历
    AVC1与H264的差别
    oracle递归函数
    全部编程皆为Web编程
    JavaScript--语法2--语句结构
    JavaScript--变量和运算符
  • 原文地址:https://www.cnblogs.com/zhoushuyu/p/8664563.html
Copyright © 2011-2022 走看看