【BZOJ4945】[Noi2017]游戏

题目描述

题解:2-SAT学艺不精啊!

这题一打眼看上去是个3-SAT?哎?3-SAT不是NPC吗?哎?这题x怎么只有8个?暴力走起!

因为x要么不是A要么不是B,所以直接2^8枚举所有x就行了。然后就变成了一个2-SAT问题。假设有两场游戏1,2,分别可以使用的地图为A1,A2,B1,B2,如果有一个限制是1 A 2 A,那么选A1就必须选A2,然后我这个沙茶就开开心心的拿了55分。

为什么不对?我建出来的图显然不对偶啊!考虑逆否命题,选A1就必须选A2,那么选B2就必须选B1啊!然后跑2-SAT+拓扑排序输出方案即可。

特别地,如果选A1就必须选A2,但是A1不能选,那么我们可以直接无视这个条件。如果选A1就必须选A2,但是A2不能选,那么A1也不能选, 于是就连一条A1->B1的边(你可以理解为这样以来,在反向图中B1的拓扑序在A1前面,所以会先选B1。但真正用意好像不是这个~)。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <queue>
#define P(A,B) ((B-1)*n+A)
using namespace std;
const int maxn=200010;
int n,D,m,sum,tot,top,cnt,flag;
int to[maxn],next[maxn],head[maxn],tt[maxn],nn[maxn],hh[maxn],op[maxn],ot[maxn];
int del[maxn],ins[maxn],dep[maxn],low[maxn],sta[maxn],bel[maxn],pos[10];
int pa[maxn],pb[maxn],pc[maxn],pd[maxn],color[maxn],d[maxn];
char str[maxn],c1[5],c2[5],ans[maxn];
queue<int> q;
void add(int a,int b)
{
to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
}
void ADD(int a,int b)
{
tt[cnt]=b,nn[cnt]=hh[a],hh[a]=cnt++;
}
void tarjan(int x)
{
dep[x]=low[x]=++tot,ins[x]=1,sta[++top]=x;
for(int i=hh[x];i!=-1;i=nn[i])
{
int y=tt[i];
if(!dep[y]) tarjan(y),low[x]=min(low[x],low[y]);
else if(ins[y]) low[x]=min(low[x],dep[y]);
}
if(dep[x]==low[x])
{
int t;
sum++;
do
{
t=sta[top--],ins[t]=0,bel[t]=sum;
}while(t!=x);
}
}
void check()
{
memset(hh,-1,sizeof(hh));
memset(dep,0,sizeof(dep));
cnt=tot=sum=0;
int i,a,b,c;
for(i=1;i<=n;i++)
{
a=(str[i]-'a')*n+i,b=(a-1+n)%(3*n)+1,c=(b-1+n)%(3*n)+1;
del[a]=1,del[b]=del[c]=0;
op[b]=c,op[c]=b;
}
for(i=1;i<=m;i++)
{
a=pc[i]*n+pa[i],b=pd[i]*n+pb[i];
if(a==b||del[a]) continue;
if(pa[i]==pb[i]||del[b])
{
ADD(a,op[a]);
continue;
}
ADD(op[b],op[a]),ADD(a,b);
}
for(i=1;i<=3*n;i++) if(!del[i]&&!dep[i]) tarjan(i);
for(i=1;i<=3*n;i++)
{
if(del[i]) continue;
if(bel[op[i]]==bel[i]) return ;
else ot[bel[op[i]]]=bel[i],ot[bel[i]]=bel[op[i]];
}
flag=1;
}
void dfs(int x)
{
if(x==D+1)
{
check();
return ;
}
str[pos[x]]='a',dfs(x+1);
if(flag) return ;
str[pos[x]]='b',dfs(x+1);
}
void DFS(int x)
{
if(color[x]!=-1) return ;
color[x]=0,color[ot[x]]=1;
for(int i=head[x];i!=-1;i=next[i]) DFS(to[i]);
}
int main()
{
scanf("%d%d%s%d",&n,&D,str+1,&m);
int i,j,u;
for(i=1;i<=n;i++) if(str[i]=='x') pos[++pos[0]]=i;
for(i=1;i<=m;i++)
{
scanf("%d%s%d%s",&pa[i],c1,&pb[i],c2),pc[i]=c1[0]-'A',pd[i]=c2[0]-'A';
}
dfs(1);
if(!flag)
{
printf("-1");
return 0;
}
memset(head,-1,sizeof(head));
memset(color,-1,sizeof(color));
cnt=0;
for(i=1;i<=3*n;i++) if(!del[i])
{
for(j=hh[i];j!=-1;j=nn[j]) if(bel[tt[j]]!=bel[i]) d[bel[i]]++,add(bel[tt[j]],bel[i]);
}
for(i=1;i<=sum;i++) if(!d[i]) q.push(i);
while(!q.empty())
{
u=q.front(),q.pop();
for(i=head[u];i!=-1;i=next[i])
{
d[to[i]]--;
if(!d[to[i]]) q.push(to[i]);
}
if(color[u]!=-1) continue;
DFS(ot[u]);
}
for(i=1;i<=3*n;i++) if(!del[i]&&color[bel[i]]==1) ans[(i-1)%n]=(i-1)/n+'A';
printf("%s",ans);
return 0;
}

【BZOJ4945】[Noi2017]游戏 2-SAT的更多相关文章

  1. [BZOJ4945][Noi2017]游戏 2-sat

    对于所有的x,我们枚举他的地图类型,事实上我们只需要枚举前两种地形就可以覆盖所有的情况. 之后就变成了裸的2-sat问题. 对于一个限制,我们分类讨论: 1.h[u]不可选,跳过 2.h[v]不可选, ...

  2. [bzoj4945][Noi2017]游戏

    题目大意:有$n$个位置,有三种数,每个位置只可以填一种数,$d(d\leqslant8)$个位置有三种选择,其他位置只有两种选择.有一些限制,表示第$i$个位置选了某种数,那么第$j$个位置就只能选 ...

  3. P3825 [NOI2017]游戏

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

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

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

  5. BZOJ4945 & 洛谷3825 & UOJ317:[NOI2017]游戏——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=4945 https://www.luogu.org/problemnew/show/P3825 ht ...

  6. 【bzoj4945】[Noi2017]游戏(搜索+2-sat)

    bzoj 洛谷 题意: 现在有\(a,b,c\)三种车,每个赛道可能会存在限制:\(a\)表示不能选择\(a\)类型的赛车,\(b,c\)同理:\(x\)表示该赛道不受限制,但\(x\)类型的个数$\ ...

  7. 并不对劲的bzoj4945:loj2305:uoj317:p3825[NOI2017]游戏

    题目大意 2-SAT,其中有\(d\)(\(d\leq 8\))个点是\(3-SAT\). 题解 枚举\(d\)个点不取三个中(假设三个为\(a,b,c\))的哪一个,然后整体变成做\(2-SAT\) ...

  8. bzoj3825 NOI2017 游戏

    题目背景 狂野飙车是小 L 最喜欢的游戏.与其他业余玩家不同的是,小 L 在玩游戏之余,还精于研究游戏的设计,因此他有着与众不同的游戏策略. 题目描述 小 L 计划进行nn 场游戏,每场游戏使用一张地 ...

  9. [NOI2017]游戏(2-SAT)

    这是约半年前写的题解了,就搬过来吧 感觉这是NOI2017最水的一题(当然我还是不会2333),因为是一道裸的2-SAT.我就是看着这道题学的2-SAT 算法一:暴力枚举.对于abc二进制枚举,对于x ...

随机推荐

  1. n!在k进制下的后缀0

    问n! 转化成k进制后的位数和尾数的0的个数.[UVA 10061 How many zeros and how many digits?] Given a decimal integer numbe ...

  2. python 关键词

    一.python关键字   1. and :表示逻辑判断 [与] a = '1' b = 1 if a and b: print('Hello Python') 2.as :单独没有实际意思,常与wi ...

  3. Ruby on rails初体验(三)

    继体验一和体验二中的内容,此节将体验二中最开始的目标来实现,体验二中已经将部门添加的部分添加到了公司的show页面,剩下的部分是将部门列表也添加到公司的显示页面,整体思路和体验二中相同,但是还是会有点 ...

  4. linux查看端口状态相关命令

    netstat netstat 命令应用是比较频繁的,比如查看端口占用啦,查看端口进程啦,这些时候都是有必要的. netstat命令各个参数说明如下: -t : 指明显示TCP端口 -u : 指明显示 ...

  5. Android开发常见的Activity中内存泄漏及解决办法

    上一篇文章楼主提到由Context引发的内存泄漏,在这一篇文章里,我们来谈谈Android开发中常见的Activity内存泄漏及解决办法.本文将会以“为什么”“怎么解决”的方式来介绍这几种内存泄漏. ...

  6. http://blog.csdn.net/LANGXINLEN/article/details/50421988

    GitHub上史上最全的Android开源项目分类汇总 今天在看博客的时候,无意中发现了 @Trinea在GitHub上的一个项目 Android开源项目分类汇总, 由于类容太多了,我没有一个个完整地 ...

  7. 【音乐App】—— Vue-music 项目学习笔记:歌手页面开发

    前言:以下内容均为学习慕课网高级实战课程的实践爬坑笔记. 项目github地址:https://github.com/66Web/ljq_vue_music,欢迎Star. 一.歌手页面布局与设计 需 ...

  8. script脚本中写不写$(document).ready(function() {});的差别

    $(document).ready() 里的代码是在页面内容都载入完才运行的,假设把代码直接写到script标签里.当页面载入完这个script标签就会运行里边的代码了,此时假设你标签里运行的代码调用 ...

  9. Iptables实现公网IP DNAT/SNAT

    Iptables实现NAT是最基本的功能,大部分家用路由都是基于其SNAT方式上网,使用Iptables实现外网DNAT也很简单,不过经常会出现不能正常NAT的现象.以下命令将客户端访问1.1.1.1 ...

  10. C#实现多级子目录Zip压缩解压实例 NET4.6下的UTC时间转换 [译]ASP.NET Core Web API 中使用Oracle数据库和Dapper看这篇就够了 asp.Net Core免费开源分布式异常日志收集框架Exceptionless安装配置以及简单使用图文教程 asp.net core异步进行新增操作并且需要判断某些字段是否重复的三种解决方案 .NET Core开发日志

    C#实现多级子目录Zip压缩解压实例 参考 https://blog.csdn.net/lki_suidongdong/article/details/20942977 重点: 实现多级子目录的压缩, ...