从题面中四元组\((i,h_i,j,h_j)\)限制选择车子型号,不难想到这题要用\(2-SAT\)解决。

考虑转化为\(2-SAT\)模型,发现除地图\(x\)外,其他地图都只有两种车子型号可以参加,那么就把这两种型号转化为两种状态。

若\(S_i=a\),则状态为\(B\)和\(C\)。

若\(S_i=b\),则状态为\(A\)和\(C\)。

若\(S_i=c\),则状态为\(A\)和\(B\)。

然后讨论四元组的情况,设\(i\)为输入的状态,\(i^\prime\)为另一个状态。

若在第\(i\)场,\(h_i\)不可用,则不进行连边。

若在第\(i\)场,\(h_i\)可用,在第\(j\)场,\(h_j\)不可用,则从\(i\)向\(i^\prime\)连边,表示不能选\(i\)。

若两个都可用,则从\(i\)向\(j\)连边,表示若选\(i\),则一定选\(j\),同时从\(j^\prime\)向\(i^\prime\)连边,这里表示若没有选\(j\),则一定没有选\(i\)。

继续考虑如何处理地图\(x\),发现其数量\(d\leqslant8\),数据规模很小,那么我们就可以用\(dfs\)将其所有可能的情况枚举一遍,再检查是否合法。

我们只需考虑地图\(x\)等价于地图\(a\)和地图\(b\)两种情况,因为此时已经包括\(A,B,C\)三种车型了。

时间复杂度为\(O(2^d(n+m))\)。

实现细节还是蛮多的,不清楚的就看代码吧。

\(code:\)

#include<bits/stdc++.h>
#define maxn 1000010
using namespace std;
template<typename T> inline void read(T &x)
{
x=0;char c=getchar();bool flag=false;
while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
if(flag)x=-x;
}
int n,d,m,x_cnt;
bool flag;
char s[maxn],a[5],b[5],c1[maxn],c2[maxn];
int pos[maxn];
struct node
{
int x,y;
char a,b;
}t[maxn];
struct edge
{
int to,nxt;
}e[maxn];
int head[maxn],edge_cnt;
void add(int from,int to)
{
e[++edge_cnt]=(edge){to,head[from]};
head[from]=edge_cnt;
}
int dfn_cnt,co_cnt,top;
int dfn[maxn],low[maxn],co[maxn],st[maxn];
bool vis[maxn];
void tarjan(int x)
{
dfn[x]=low[x]=++dfn_cnt;
st[++top]=x;
vis[x]=true;
for(int i=head[x];i;i=e[i].nxt)
{
int y=e[i].to;
if(!dfn[y])
{
tarjan(y);;
low[x]=min(low[x],low[y]);
}
else if(vis[y])
low[x]=min(low[x],dfn[y]);
}
if(low[x]==dfn[x])
{
co_cnt++;
int now;
do
{
now=st[top--];
vis[now]=false;
co[now]=co_cnt;
}while(now!=x);
}
}
bool check()
{
for(int i=1;i<=2*n;++i)
if(!dfn[i])
tarjan(i);
for(int i=1;i<=n;++i)
if(co[i]==co[i+n])
return false;
return true;
}
void clear()
{
edge_cnt=dfn_cnt=co_cnt=top=0;
memset(st,0,sizeof(st));
memset(co,0,sizeof(co));
memset(dfn,0,sizeof(dfn));
memset(low,0,sizeof(low));
memset(vis,0,sizeof(vis));
memset(head,0,sizeof(head));
}
void work()
{
clear();
for(int i=1;i<=m;++i)
{
int x=t[i].x,y=t[i].y;
char a=t[i].a,b=t[i].b;
if(s[x]==a) continue;
if(s[y]==b)
{
add(x+(a==c2[x])*n,x+(a==c1[x])*n);
continue;
}
add(x+(a==c2[x])*n,y+(b==c2[y])*n);
add(y+(b==c1[y])*n,x+(a==c1[x])*n);
}
if(check())
{
flag=true;
for(int i=1;i<=n;i++)
{
if(co[i]<co[i+n]) printf("%c",c1[i]);
else printf("%c",c2[i]);
}
}
}
void dfs(int x)
{
if(flag) return;
if(x==d+1)
{
work();
return;
}
int now=pos[x];
s[now]='A',c1[now]='B',c2[now]='C',dfs(x+1);
s[now]='B',c1[now]='A',c2[now]='C',dfs(x+1);
}
int main()
{
read(n),read(d);
scanf("%s",s+1);
for(int i=1;i<=n;++i)
{
s[i]+='A'-'a';
if(s[i]=='A') c1[i]='B',c2[i]='C';
if(s[i]=='B') c1[i]='A',c2[i]='C';
if(s[i]=='C') c1[i]='A',c2[i]='B';
if(s[i]=='X') pos[++x_cnt]=i;
}
read(m);
for(int i=1;i<=m;++i)
{
read(t[i].x),scanf("%s",a),read(t[i].y),scanf("%s",b);
t[i].a=a[0],t[i].b=b[0];
}
dfs(1);
if(!flag) printf("-1");
return 0;
}

题解 洛谷 P3825 【[NOI2017]游戏】的更多相关文章

  1. 洛谷 P3825 [NOI2017]游戏 【2-SAT+状压】

    UOJ和洛谷上能A,bzoj 8ms即WA,现在也不是知道为啥--因为我太弱了 先看数据范围发现d非常小,自然想到了状压. 所以先假装都是只能跑两种车的,这显然就是个2-SAT问题了:对于x场没有hx ...

  2. 洛谷P3825 [NOI2017]游戏(2-SAT)

    传送门 果然图论的题永远建图最麻烦……看着题解代码的建图过程真的很珂怕…… 先不考虑地图$x$,那么每一个地图都只能用两种赛车,于是我们可以用2-SAT来搞,用$i$表示这个地图能用的第一辆车,$i' ...

  3. 洛谷3825 [NOI2017]游戏 2-sat

    原文链接http://www.cnblogs.com/zhouzhendong/p/8146041.html 题目传送门 - 洛谷3825 题解 我们考虑到地图中x的个数很少,最多只有8个. 所以我们 ...

  4. P3825 [NOI2017]游戏

    题目 P3825 [NOI2017]游戏 做法 \(x\)地图外的地图好做,模型:\((x,y)\)必须同时选\(x \rightarrow y,y^\prime \rightarrow x^\pri ...

  5. 洛谷 P2197 nim游戏

    洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...

  6. 洛谷 P1965 转圈游戏

    洛谷 P1965 转圈游戏 传送门 思路 每一轮第 0 号位置上的小伙伴顺时针走到第 m 号位置,第 1 号位置小伙伴走到第 m+1 号位置,--,依此类推,第n − m号位置上的小伙伴走到第 0 号 ...

  7. [Luogu P3825] [NOI2017] 游戏 (2-SAT)

    [Luogu P3825] [NOI2017] 游戏 (2-SAT) 题面 题面较长,略 分析 看到这些约束,应该想到这是类似2-SAT的问题.但是x地图很麻烦,因为k-SAT问题在k>2的时候 ...

  8. 【题解】洛谷P1070 道路游戏(线性DP)

    次元传送门:洛谷P1070 思路 一开始以为要用什么玄学优化 没想到O3就可以过了 我们只需要设f[i]为到时间i时的最多金币 需要倒着推回去 即当前值可以从某个点来 那么状态转移方程为: f[i]= ...

  9. 【流水调度问题】【邻项交换对比】【Johnson法则】洛谷P1080国王游戏/P1248加工生产调度/P2123皇后游戏/P1541爬山

    前提说明,因为我比较菜,关于理论性的证明大部分是搬来其他大佬的,相应地方有注明. 我自己写的部分换颜色来便于区分. 邻项交换对比是求一定条件下的最优排序的思想(个人理解).这部分最近做了一些题,就一起 ...

随机推荐

  1. 新一代APM链路监控选型的一个总结重点是skywalking和pinpoint的对比

    链路监控选型的一个比较:1.cat框架:需要对业务代码有较强的侵入性,对代码的侵入性很大,集成成本较高,风险较大:2.zipkin框架:仅支持spring cloud,不支持dubbo,功能及其简单, ...

  2. js基础练习题(4)

    9.对象 阅读代码,回答问题 function User(name) { var name1 = name; this.name2 = name; function getName1() { retu ...

  3. 如何通过Elasticsearch Scroll快速取出数据,构造pandas dataframe — Python多进程实现

    首先,python 多线程不能充分利用多核CPU的计算资源(只能共用一个CPU),所以得用多进程.笔者从3.7亿数据的索引,取200多万的数据,从取数据到构造pandas dataframe总共大概用 ...

  4. 简单的Linq查询语句

    下面我来我大家介绍几种简单的查询方式. 1.简单语法 这个LINQ语句的第一个关键字是from,from后面加的是范围变量,范围变量后加in,后加上事先实例化的模型,然后点出数据的来源. List是列 ...

  5. 相邻元素之间的margin合并问题

    任何元素都可以设置border 设置宽高可能无效 行内元素设置padding,margin上下是无效的,左右是有效的 外边距合并:指的是,当两个垂直外边距相遇时,它们将形成一个外边距. 合并后的外边距 ...

  6. Html5中input新增的表单元素和属性介绍。

    input标签主要用于Web表单的创建交互,以便接受来自用户的数据. 我们通过更改type属性的值,来实现不同的输入类型.在以前的写法中表单元素必须放在form元素所包含的里面,而在html5中,我们 ...

  7. NOIP 2016 洛谷 P2827 蚯蚓 题解

    题目传送门 展开 题目描述 本题中,我们将用符号[c]表示对c向下取整,例如:[3.0」= [3.1」=[3.9」=3.蛐蛐国最近蚯蚓成灾了!隔壁跳 蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去请神刀手 ...

  8. day06 可变不可变类型

    1.可变不可变类型 可变类型 定义:值改变,id不变,改的是原值 不可变类型 定义:值改变,id也变了,证明是产生了新的值没有改变原值 验证 x = 10 print(id(x)) x = 11 pr ...

  9. Navigation Nightmare POJ - 1984

    Navigation Nightmare Farmer John's pastoral neighborhood has N farms (2 <= N <= 40,000), usual ...

  10. 【GIT】git详解

    目录 一.基础使用 二.分支管理 三.提交树操作 四.复杂工作流处理 ----------------------------------------------------------------- ...