LG3825 [NOI2017] 游戏 题解
算是真正懂 2-sat 了,难绷随机眺水题直接一发紫,不过也还好。
题目描述
小 L 计划进行 \(n\) 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。
小 L 的赛车有三辆,分别用大写字母 \(A\)、\(B\)、\(C\) 表示。地图一共有四种,分别用小写字母 \(x\)、\(a\)、\(b\)、\(c\) 表示。
其中,赛车 \(A\) 不适合在地图 \(a\) 上使用,赛车 \(B\) 不适合在地图 \(b\) 上使用,赛车 \(C\) 不适合在地图 \(c\) 上使用,而地图 \(x\) 则适合所有赛车参加。
适合所有赛车参加的地图并不多见,最多只会有 \(d\) 张。
\(n\) 场游戏的地图可以用一个小写字母组成的字符串描述。例如:\(S=\texttt{xaabxcbc}\) 表示小 L 计划进行 \(8\) 场游戏,其中第 \(1\) 场和第 \(5\) 场的地图类型是 \(x\),适合所有赛车,第 \(2\) 场和第 \(3\) 场的地图是 \(a\),不适合赛车 \(A\),第 \(4\) 场和第 \(7\) 场的地图是 \(b\),不适合赛车 \(B\),第 \(6\) 场和第 \(8\) 场的地图是 \(c\),不适合赛车 \(C\)。
小 L 对游戏有一些特殊的要求,这些要求可以用四元组 $ (i, h_i, j, h_j) $ 来描述,共 \(m\) 个四元组,表示若在第 \(i\) 场使用型号为 \(h_i\) 的车子,则第 \(j\) 场游戏要使用型号为 \(h_j\) 的车子。
你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。
如果无解,输出
-1
。
数据范围
\(d\leq 8,n\leq 5\times 10^4,m\leq 10^5\)
题解
呃呃呃,这个限制就 2-sat 板子,我们先假设对于四元组 \((i,h_i,j,h_j)\),\(S_i\) 和 \(S_j\) 均不为 \(x\),即第 \(i\) 场和第 \(j\) 场均只能使用两种型号的车子,不妨假设为 \(h_i,h_i',h_j,h_j'\)。
然后由于 \(x\) 的位置很少,直观上我们可以考虑枚举 \(x\) 的字母,转化为每个每场只有两种车子可以选择,即标准 2-sat 求解。又由于我们假设 \(x\) 字母为 \(a\) 时,跑一边可以同时判断这一场车子为 \(b\) 或 \(c\) 是否有解,因此我们只需要枚举 \(x\) 为 \(a\) 和 \(b\) 即可,这部分对复杂度的贡献为 \(2^d\)。
因为我做的时候忘记 2-sat 是啥了,所以这里就再回顾一下 2-sat 的原理和做法。
最典的 2-sat 的限制就像洛谷模板一样,条件的形式为 「\(x_i\) 为 true
/ false
或 \(x_j\) 为 true
/ false
」。比如 「\(x_1\) 为真或 \(x_2\) 为假」、「\(x_7\) 为假或 \(x_2\) 为假」。
这个或的意思就是两个条件至少一个为真,我们以「\(x_1\) 为真或 \(x_2\) 为假」为例子。三种合法的情况为:
- \(x_1=true,x_2=flase\)
- \(x_1=true,x_2=true\)
- \(x_1=flase,x_2=flase\)
因此我们可以发现:
- 当 \(x_1=flase\) 时,\(x_2\) 一定为 \(flase\)。
- 当 \(x_2=true\) 时,\(x_1\) 一定为 \(true\)。
那么我们把 \(x_1=flase\)、\(x_1=true\) 之类的看成点,那么上面这两条关系就可以连边了:
- \((x_1=f)\to (x_2=f)\)
- \((x_2=t)\to (x_1=t)\)
那么如果 \((x_i=f)\) 和 \((x_i=t)\) 在一个联通分量里面,这些条件就是互相矛盾的,否则可以找到解。
可以证明,每个 \(x_i\) 选取缩点后拓扑序较大的点可以作为一个答案。
不妨假设 \((x_i=t)\) 的拓扑序大于 \((x_i=f)\) 的拓扑序。如果他们在缩点后 DAG 上不连通,则 \(x_i\) 选 \(t\) 或 \(f\) 均可;如果联通,则假设 \(x_i=f\) ,最后得到 \(x_i=t\),矛盾,而 \(x_i=t\) 合法。因此选拓扑序较大的,即 \((x_i=t)\)。
又因为 tarjan 缩点的时候强连通分量的编号越大,拓扑序越小,不需要额外再跑一次拓扑。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int>ttfa;
const int N=200005;
char s[N],t[N],f[N];
int n,m,pos[N],q;
struct ques{int u,v;char opt_u,opt_v;}lis[N];
vector<int>tar[N*3];
int dfn[N],low[N],tim,stk[N],top,tot,col[N],vis[N];
void clear(){
tim=top=tot=0;
for(int i=1;i<=3*n;++i){
dfn[i]=low[i]=stk[i]=col[i]=vis[i]=0;
tar[i].clear();
}
}
void tarjan(int u){
dfn[u]=low[u]=++tim;
stk[++top]=u;vis[u]=1;
for(auto v:tar[u]){
if(!dfn[v]){
tarjan(v);
low[u]=min(low[u],low[v]);
}else if(vis[v])
low[u]=min(low[u],dfn[v]);
}
if(dfn[u]==low[u]){
++tot;
do{
col[u]=tot;
u=stk[top--];
vis[u]=0;
}while(dfn[u]!=low[u]);
}
}
bool calc(){
clear();
for(int i=1;i<=n;++i){
if(s[i]=='a')t[i]='b',f[i]='c';
if(s[i]=='b')t[i]='a',f[i]='c';
if(s[i]=='c')t[i]='a',f[i]='b';
}
for(int i=1;i<=q;++i){
int tu=0,fu=0,tv=0,fv=0;
tu=n*(t[lis[i].u]-'a')+lis[i].u;
fu=n*(f[lis[i].u]-'a')+lis[i].u;
if(f[lis[i].u]==lis[i].opt_u)swap(tu,fu);
tv=n*(t[lis[i].v]-'a')+lis[i].v;
fv=n*(f[lis[i].v]-'a')+lis[i].v;
if(f[lis[i].v]==lis[i].opt_v)swap(tv,fv);
if(s[lis[i].u]==lis[i].opt_u)continue;
if(s[lis[i].v]==lis[i].opt_v){
tar[tu].push_back(fu);
}else{
tar[tu].push_back(tv);
tar[fv].push_back(fu);
}
}
for(int i=1;i<=3*n;++i)if(!dfn[i])tarjan(i);
for(int i=1;i<=n;++i){
int tu=n*(t[i]-'a')+i,fu=n*(f[i]-'a')+i;
if(col[tu]==col[fu])return 0;
}
return 1;
}
int main(){
scanf("%d%d",&n,&m);m=0;
scanf("%s",s+1);
for(int i=1;i<=n;++i){
if(s[i]=='x')pos[++m]=i;
}
scanf("%d",&q);
for(int i=1;i<=q;++i){
scanf("%d %c %d %c",&lis[i].u,&lis[i].opt_u,&lis[i].v,&lis[i].opt_v);
lis[i].opt_u+=32;lis[i].opt_v+=32;
}
for(int S=0;S<(1<<m);++S){
for(int i=1;i<=m;++i){
if((S>>(i-1))&1){
s[pos[i]]='b';
}else s[pos[i]]='a';
}
if(!calc())continue;
for(int i=1;i<=n;++i){
int tu=n*(t[i]-'a')+i,fu=n*(f[i]-'a')+i;
if(col[tu]<col[fu])putchar(t[i]-'a'+'A');
else putchar(f[i]-'a'+'A');
}puts("");
return 0;
}
puts("-1");
return 0;
}
本文作者:BigSmall_En
本文链接:https://www.cnblogs.com/BigSmall-En/p/18703455
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全网最简单!3分钟用满血DeepSeek R1开发一款AI智能客服,零代码轻松接入微信、公众号、小程
· .NET 10 首个预览版发布,跨平台开发与性能全面提升
· 《HelloGitHub》第 107 期
· 全程使用 AI 从 0 到 1 写了个小工具
· 从文本到图像:SSE 如何助力 AI 内容实时呈现?(Typescript篇)