Luogu P3825 [NOI2017]游戏
这道题看上去NPC啊,超级不可做的样子。
我们先分析一下简单的情形:没有\(x\)地图
此时每个地图由于限制掉一种汽车,那么显然只会有两种选择。
再考虑到限制的情况,那么大致做法就很显然了——2-SAT
首先是拆点,对于每张地图\(i\)拆成\(2i-1\)与\(2i\)表示这张地图选择能用的车的第一辆还是第二辆。
比如如果\(s_i=b\),那么\(2i-1\)表示选择\(A\)车,\(2i\)表示选择\(B\)车。
现在开始考虑选择的限制,对于每一个限制\((u,x,v,y)\),我们分情况讨论:
- 当\(s_u=x\),说明这个限制没有意义,直接无视即可。
- 当\(s_u\not=x\)且\(s_v=y\)时,说明这时\(u\)是绝对不能选\(x\)对应的点的。为了在建图中体现出来我们直接从\(x\)对应的点向另一个点连边即可。
- 当\(s_u\not=x\)且\(s_v\not= y\)时,显然讲\(x\)对应的点向\(y\)对应的点连边。但是不要忘了2-SAT建图的对称性,我们还要从\(y\)对应的点的反点向\(x\)对应的点的反点连边。这样的意义也十分明确了吧,因为每个地图都必须做出选择,选择\(y\)对应的点的反点就使得\(u\)没有其他选择了。
然后就是用Tarjan跑SCC的过程了,这里不再赘述。值得一提的是Tarjan的标号顺序是按照拓扑序的逆序(因为是DFS)跑出来的,所以可以直接用标号来输出方案。
那么接下来就是考虑万恶的\(x\)地图了
我们发现这样并没有什么好的建图方法,然后翻到下面一看数据范围\(d\le8\)
然后一种特别naive的想法就是\(3^d\)枚举每个\(x\)地图是什么类型。然后再乘上Tarjan的复杂度直接爆炸。
我们想一下我们枚举的本质:
- 如果对于一个\(x\)地图取\(a\)即意味这只能用车\(B,C\)
- 如果对于一个\(x\)地图取\(b\)即意味这只能用车\(A,C\)
- 如果对于一个\(x\)地图取\(c\)即意味这只能用车\(A,B\)
然后我们惊奇地发现第三种情况已经被前两种情况包含掉了,所以复杂度变为\(2^d(n+m)\)
如果对于爆搜会被无解的数据卡满的同志们可以直接随机跑,实测这样也可以过。
不过实践的时候细节巨多,还是挺烦人的。
CODE
#include<cstdio>
#include<cctype>
#include<cstdlib>
#include<cstring>
#define RI register int
#define Ms(f,x) memset(f,x,sizeof(f))
using namespace std;
const int N=50005;
struct ques
{
int x,y; char p1,p2;
}q[N<<1]; int n,m,d,tot,c[N],ukn[10],pt; char ch;
inline int T(char ch)
{
if (ch>='a'&&ch<='c') return ch-'a'+1;
else return ch-'A'+1;
}
inline int Id(int x,int y)
{
switch (x)
{
case 1:return y!=3?1:0;break;
case 2:return y!=3?1:0;break;
case 3:return y!=2?1:0;break;
}
}
inline char C(int x,int y)
{
switch (x)
{
case 1:return y!=2?'B':'C';break;
case 2:return y!=2?'A':'C';break;
case 3:return y!=2?'A':'B';break;
}
}
class FileInputOutput
{
private:
#define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
#define S 1<<21
char Fin[S],Fout[S],*A,*B; int Ftop;
public:
FileInputOutput() { Ftop=0; A=B=Fin; }
inline void gc(char &ch)
{
while (!isalpha(ch=tc()));
}
inline void pc(char ch)
{
Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch);
}
inline void read(int &x)
{
x=0; char ch; while (!isdigit(ch=tc()));
while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
}
inline void Fend(void)
{
fwrite(Fout,1,Ftop,stdout);
}
#undef S
#undef tc
}F;
class Two_SAT_Solver
{
private:
#define add(x,y) e[++cnt]=(edge){y,head[x]},head[x]=cnt
struct edge
{
int to,next;
}e[N<<2]; int head[N<<1],cnt,dfn[N<<1],low[N<<1],scc,col[N<<1],stack[N<<1],top,tot; bool vis[N];
inline int min(int a,int b)
{
return a<b?a:b;
}
#define to e[i].to
inline void Tarjan(int now)
{
dfn[now]=low[now]=++tot; stack[++top]=now; vis[now]=1;
for (RI i=head[now];i;i=e[i].next)
if (!dfn[to]) Tarjan(to),low[now]=min(low[now],low[to]);
else if (vis[to]) low[now]=min(low[now],dfn[to]);
if (low[now]==dfn[now])
{
col[now]=++scc; vis[now]=0; while (stack[top]!=now)
col[stack[top]]=scc,vis[stack[top--]]=0; --top;
}
}
#undef to
public:
inline void build(void)
{
for (RI i=1;i<=m;++i)
{
int x=q[i].x,y=q[i].y,p1=T(q[i].p1),p2=T(q[i].p2);
if (c[x]==p1) continue; int numx=x<<1,numy=y<<1;
if (c[y]==p2) add(numx-Id(c[x],p1),numx-(Id(c[x],p1)^1)); else
add(numx-Id(c[x],p1),numy-Id(c[y],p2)),add(numy-(Id(c[y],p2)^1),numx-(Id(c[x],p1)^1));
}
}
inline void check(void)
{
RI i; int lim=n<<1; for (i=1;i<=lim;++i) if (!dfn[i]) Tarjan(i);
for (i=1;i<=n;++i) if (col[(i<<1)-1]==col[i<<1]) return;
for (i=1;i<=n;++i) if (col[(i<<1)-1]<col[i<<1]) F.pc(C(c[i],1)); else F.pc(C(c[i],2));
F.Fend(); exit(0);
}
inline void clear(void)
{
cnt=tot=scc=0; Ms(head,0); Ms(dfn,0);
}
}S;
int main()
{
//freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
RI i,j; for (F.read(n),F.read(d),i=1;i<=n;++i)
{
F.gc(ch); if (ch!='x') c[i]=T(ch); else ukn[++pt]=i;
}
for (F.read(m),i=1;i<=m;++i) F.read(q[i].x),F.gc(q[i].p1),F.read(q[i].y),F.gc(q[i].p2);
for (tot=(1<<d)-1,i=0;i<=tot;++i)
{
for (j=1;j<=d;++j) c[ukn[j]]=((i>>j-1)&1)+1;
S.build(); S.check(); S.clear();
}
return F.pc('-'),F.pc('1'),F.Fend(),0;
}
Luogu P3825 [NOI2017]游戏的更多相关文章
- [Luogu P3825] [NOI2017] 游戏 (2-SAT)
[Luogu P3825] [NOI2017] 游戏 (2-SAT) 题面 题面较长,略 分析 看到这些约束,应该想到这是类似2-SAT的问题.但是x地图很麻烦,因为k-SAT问题在k>2的时候 ...
- P3825 [NOI2017]游戏
题目 P3825 [NOI2017]游戏 做法 \(x\)地图外的地图好做,模型:\((x,y)\)必须同时选\(x \rightarrow y,y^\prime \rightarrow x^\pri ...
- Luogu 3825 [NOI2017]游戏
Luogu的spj现在挂了,要去其他OJ提交. 2-SAT 发现如果不考虑$x$的情况,这就成为一个2-SAT的裸题了,我们有$O(n + m)$的方法可以解决它. 那加上$x$的情况怎么弄……岂不是 ...
- 洛谷P3825 [NOI2017]游戏(2-SAT)
传送门 果然图论的题永远建图最麻烦……看着题解代码的建图过程真的很珂怕…… 先不考虑地图$x$,那么每一个地图都只能用两种赛车,于是我们可以用2-SAT来搞,用$i$表示这个地图能用的第一辆车,$i' ...
- 洛谷 P3825 [NOI2017]游戏 【2-SAT+状压】
UOJ和洛谷上能A,bzoj 8ms即WA,现在也不是知道为啥--因为我太弱了 先看数据范围发现d非常小,自然想到了状压. 所以先假装都是只能跑两种车的,这显然就是个2-SAT问题了:对于x场没有hx ...
- 并不对劲的bzoj4945:loj2305:uoj317:p3825[NOI2017]游戏
题目大意 2-SAT,其中有\(d\)(\(d\leq 8\))个点是\(3-SAT\). 题解 枚举\(d\)个点不取三个中(假设三个为\(a,b,c\))的哪一个,然后整体变成做\(2-SAT\) ...
- 【BZOJ4945】[Noi2017]游戏 2-SAT
[BZOJ4945][Noi2017]游戏 题目描述 题解:2-SAT学艺不精啊! 这题一打眼看上去是个3-SAT?哎?3-SAT不是NPC吗?哎?这题x怎么只有8个?暴力走起! 因为x要么不是A要么 ...
- [luogu]P1070 道路游戏[DP]
[luogu]P1070 道路游戏 题目描述小新正在玩一个简单的电脑游戏.游戏中有一条环形马路,马路上有 n 个机器人工厂,两个相邻机器人工厂之间由一小段马路连接.小新以某个机器人工厂为起点,按顺时针 ...
- 题解 洛谷 P3825 【[NOI2017]游戏】
从题面中四元组\((i,h_i,j,h_j)\)限制选择车子型号,不难想到这题要用\(2-SAT\)解决. 考虑转化为\(2-SAT\)模型,发现除地图\(x\)外,其他地图都只有两种车子型号可以参加 ...
随机推荐
- Java并发编程(十)阻塞队列
使用非阻塞队列的时候有一个很大问题就是:它不会对当前线程产生阻塞,那么在面对类似消费者-生产者的模型时,就必须额外地实现同步策略以及线程间唤醒策略,这个实现起来就非常麻烦.但是有了阻塞队列就不一样了, ...
- [转]Docker容器可视化监控中心搭建
[原文链接]https://www.jianshu.com/p/9e47ffaf5e31?hmsr=toutiao.io&utm_medium=toutiao.io&utm_sourc ...
- 测试中Android与IOS分别关注的点
主要从本身系统的不同点.系统造成的不同点.和注意的测试点做总结 1.自身不同点 研发商:Adroid是google公司做的手机系统,IOS是苹果公司做的手机系统 开源程度:Android是开源的,IO ...
- 【第六篇】SAP ABAP7.5x新语法之SQL注入
公众号:SAP Technical 本文作者:matinal 原文出处:http://www.cnblogs.com/SAPmatinal/ 原文链接:SAP ABAP7.5x系列之SQL注入 前 ...
- 关掉 ubuntu bug 报告功能
想关掉这个: 通过服务加配置文件关掉
- 什么是Docker?
概观 Docker是推动集装箱运动的公司,也是唯一一家能够解决混合云中的每个应用的集装箱平台提供商.当今的企业面临数字化转型的压力,但受到现有应用程序和基础架构的制约,同时合理化日益多样化的云,数 ...
- vSphere ESXi 重新安装后的虚拟机恢复(转载)
安装的 ESXi 的物理主机密码忘记,登录 不上了,需要重新安装 ESXi,安装后恢复原先物理主机上的 虚拟机的方法如下(VMFS分区完好): 关于 VMFS 分区: ESXi 的安装时会划分一个分区 ...
- 【错误记录】PowerShell 超级无语的语法错误(令人怀疑人生)
曾经做过测试,本文是本章优秀测试人员的精神,必须定位到原因,不然吃不下饭.其实可以很容易绕过这种问题. 环境: PowerShell 5.1.16299.64 Windows 10 现有代码如下: # ...
- CPU指令分类
指令可以分为三类: 有运算单元参与:compq.subq 无运算单元参与:jge.movq MOV指令可以在CPU内或CPU和存储器之间传送字或字节,它传送的信息可以从寄存器到寄存器,立即数到寄存器, ...
- 【Java多线程】线程状态、线程池状态
线程状态: 线程共包括以下5种状态.1. 新建状态(New) 线程对象被创建后,就进入了新建状态.例如,Thread thread = new Thread().2. 就绪状态(Runnable) 也 ...