从题面中四元组\((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. win10使用WSL 2运行Docker Desktop,运行文件从C盘迁移到其他目录

    前言 前几天重装系统,把系统升到了Windows 10 2004,然后在安装Docker Desktop(2.3.0.3版本)时发现跟以前不太一样了.现在Docker Desktop默认使用WLS 2 ...

  2. Windows Server 2019 container容器化-Docker安装

    一.启用服务器Hyper-V,Containers特性 Install-WindowsFeature -Name Hyper-V,Containers -IncludeAllSubFeature -I ...

  3. 2020年IDEA破解激活码永久

    我想很多做开发的小伙伴和小编一样,和往常一样开机搬砖. 打开idea的时候,会收到一个个提示,也是idea许可证过期啦,需要重新激活! 那怎么办呢?我最近发现了一个相对稳定的激活码 . 亲测可用.现在 ...

  4. 并发02--JAVA内存模型

    在并发编程中,需要解决两个问题:线程间如何通信&线程间如何同步 线程同步:控制不同线程操作顺序的机制 解决这两个问题的方案有两种:共享内存&消息传递 共享内存:通过使用共享内存,隐式通 ...

  5. vue全家桶(2.7)

    3.11.1.vue-router中的全局钩子函数 在vue-router中,路由发生变化,我们可以做一些事情,例如:可以决定是否进入导航,可以决定跳转到哪里,官方文档中又叫做导航守卫 首先来看一个全 ...

  6. 报错Connection refused: connect

    版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明.本文链接:https://blog.csdn.net/qq_34266804/article/d ...

  7. Write a program to copy its input to its output, replacing each tab by \t, each backspace by \b, and each backslash by \\. This makes tabs and backspa

    #include <stdio.h> #define DBS '\\' void main() { int c; while((c=getchar())!=EOF) { if(c=='\t ...

  8. django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.2的最佳处理方法,亲测可用

    django.core.exceptions.ImproperlyConfigured: mysqlclient 1.3.13 or newer is required; you have 0.9.2 ...

  9. 多线程下的list

    前言 list 是 Python 常用的几个基本数据类型之一.正常情况下我们会对 list 有增删改查的操作,显然易见不会有任何问题.那么如果我们试着在多线程下操作list 会有问题吗? 多线程下的 ...

  10. (私人收藏)Vue.js手册及教程

    (私人收藏)Vue.js手册及教程 https://pan.baidu.com/s/1XG1XdbbdBQm7cyhQKUIrRQ5lrt Vue.js手册及教程 Vue.js 教程 Vue.js 安 ...