P9869 [NOIP2023] 三值逻辑 题解
NOIP2023 T2 三值逻辑 题解
思路
乍一看好像很并查集,而且不太难,但是,
注意到:按顺序运行这 \(m\) 条语句
事情并没有那么简单。
比如说如下情况:
x1:=T
x2:=x1
x1:=F
这时,\(x_2\)就不能简单地指向\(x_1\),否则当\(x_1\)被修改时,\(x_2\)也会被修改。
那么如何解决这个问题呢?
其实有点可持久化的感觉。我们可以对于每次修改\(x_1\)时,为它新建一个版本。以后所有形如\(x_2:=x_1\)的赋值操作,\(x_2\)都指向最新的版本。可以以边的形式存储它们的对应关系,\(x_2:=x_1\)则由\(x_2\)向\(x_1\)指一条边权为0的边(下文称为正边),\(x_2:=-x_1\)则由\(x_2\)向\(x_1\)指一条边权为1的边(下文称为负边)(这些边权是干什么的?这是一会儿要用到的神奇妙妙工具)。最终的产物像若干个栈。每个位置都有一个栈,每个栈上都摞着若干个节点。
(图挂了)
像这样。有些东西没画,各位自行脑补。
可以观察到它是一个森林,森林中每棵树上的节点的值都相等。
题干中说,要让执行了所有语句后所有变量的最终值和初始值相等。那么我们可以从每个栈的栈底向栈顶指一条正边。于是我们得到了若干个环。最终的图也就是若干基环树,但是本文中的做法并没有用到什么基环树,笔者也不会基环树。
我们要找到只能初始化为\(U\)的位置,那么什么时候一个位置只能被初始化为\(U\)呢?
第一种情况,它在最后一次赋值(“栈顶”)中被直接或间接赋值为\(U\)。这是显然的。
第二种情况,它的“栈底”(或“栈顶”)处在一个环里,且这个环中有奇数条负边。这也是显然的。
显然我们要集中精力求第二种。
依次对每一个位置进行DFS,如果DFS到被明确地赋值了的节点(形如\(x_1:=T\)),那么回溯时返回这个值,赋给回到的节点。否则返回0(也可以是-1或任何你喜欢的数。如果你也设为0,那么记得将数组初始化为-1)。
如果DFS到了一个环,且当前经过的负边个数减去上一次到这个点时的负边个数是一个奇数,那么赋值为\(U\)。可以在DFS时以参数形式传递当前经过的负边个数,用数组存储上一次到某位置时的负边个数。这时我们的负边权值为1就派上了用场,路径的权值和即是负边个数。
于是此题得解。
注意,当出现自环时,不能简单粗暴地忽略或认为无解,这样会挂40分(别问我怎么知道的);而是把它也加进图里。因为它在栈中相当于上下两节点之间的连边,是可以存在的。此时注意赋值顺序,不要像笔者一样先把节点入栈再从该节点向栈顶连边。
实现
原谅我抽象的码风
#include <iostream>
#include <cstring>
#define N 300005
int to[N],top[N],wt[N];
bool vis[N];
int a[N];
int tlen[N];
int dfs(int x,int len)
{
if(a[x]>=0)
return a[x];
if(vis[x])
{
if((len-tlen[x])&1)
return a[x]=3;
return a[x]=0;
}
vis[x]=1;
tlen[x]=len;
if(!to[x])
return a[x]=0;
int tmp=dfs(to[x],len+wt[x]);
if(tmp==3||tmp==0)
a[x]=tmp;
else
{
if(wt[x])
a[x]=3-tmp;
else
a[x]=tmp;
}
vis[x]=0;
return a[x];
}
int main()
{
int c,t;
scanf("%d%d",&c,&t);
while(t--)
{
int n,m;
scanf("%d%d",&n,&m);
memset(top,0,sizeof(top));
memset(to,0,sizeof(to));
memset(a,-1,sizeof(a));
memset(vis,0,sizeof(vis));
memset(tlen,0,sizeof(tlen));
int cnt=0;
for(int i=1;i<=n;i++)
top[i]=++cnt;
for(int i=1;i<=m;i++)
{
char opt;
std::cin>>opt;
if(opt=='+')
{
int u,v;
scanf("%d%d",&u,&v);
cnt++;
to[cnt]=top[v];
top[u]=cnt;
wt[cnt]=0;
}
if(opt=='-')
{
int u,v;
scanf("%d%d",&u,&v);
cnt++;
to[cnt]=top[v];
top[u]=cnt;
wt[cnt]=1;
}
if(opt=='T'||opt=='F'||opt=='U')
{
int v;
scanf("%d",&v);
top[v]=++cnt;
if(opt=='T')
a[cnt]=1;
else if(opt=='F')
a[cnt]=2;
else
a[cnt]=3;
}
}
for(int i=1;i<=n;i++)
if(top[i]!=i)
to[i]=top[i],wt[i]=0;
for(int i=1;i<=n;i++)
if(a[i]<0)
dfs(i,0);
int ans=0;
for(int i=1;i<=n;i++)
if(a[i]==3)
ans++;
printf("%d\n",ans);
}
}
\]
P9869 [NOIP2023] 三值逻辑 题解的更多相关文章
- 你真的会玩SQL吗?让人晕头转向的三值逻辑
你真的会玩SQL吗?系列目录 你真的会玩SQL吗?之逻辑查询处理阶段 你真的会玩SQL吗?和平大使 内连接.外连接 你真的会玩SQL吗?三范式.数据完整性 你真的会玩SQL吗?查询指定节点及其所有父节 ...
- 2016 华南师大ACM校赛 SCNUCPC 非官方题解
我要举报本次校赛出题人的消极出题!!! 官方题解请戳:http://3.scnuacm2015.sinaapp.com/?p=89(其实就是一堆代码没有题解) A. 树链剖分数据结构板题 题目大意:我 ...
- noip2016十连测题解
以下代码为了阅读方便,省去以下头文件: #include <iostream> #include <stdio.h> #include <math.h> #incl ...
- BZOJ-2561-最小生成树 题解(最小割)
2561: 最小生成树(题解) Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1628 Solved: 786 传送门:http://www.lyd ...
- Codeforces Round #353 (Div. 2) ABCDE 题解 python
Problems # Name A Infinite Sequence standard input/output 1 s, 256 MB x3509 B Restoring P ...
- 哈尔滨理工大学ACM全国邀请赛(网络同步赛)题解
题目链接 提交连接:http://acm-software.hrbust.edu.cn/problemset.php?page=5 1470-1482 只做出来四道比较水的题目,还需要加强中等题的训练 ...
- 2016ACM青岛区域赛题解
A.Relic Discovery_hdu5982 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Jav ...
- poj1399 hoj1037 Direct Visibility 题解 (宽搜)
http://poj.org/problem?id=1399 http://acm.hit.edu.cn/hoj/problem/view?id=1037 题意: 在一个最多200*200的minec ...
- 网络流n题 题解
学会了网络流,就经常闲的没事儿刷网络流--于是乎来一发题解. 1. COGS2093 花园的守护之神 题意:给定一个带权无向图,问至少删除多少条边才能使得s-t最短路的长度变长. 用Dijkstra或 ...
- CF100965C题解..
求方程 \[ \begin{array}\\ \sum_{i=1}^n x_i & \equiv & a_1 \pmod{p} \\ \sum_{i=1}^n x_i^2 & ...
随机推荐
- 2020-2021 ACM-ICPC Brazil Subregional Programming Contest
A. Sticker Album 你想要得到\(n\)张贴纸,每包礼物中等概率出现 \([A,B]\)范围内数量的贴纸,求需要买多少包礼物才能至少获得\(n\)张贴纸的期望次数 \(1 \leq n ...
- 语音转文字-Microsoft Azure Speech Service与Web Speech API实战
简介 在现代技术驱动的世界中,语音识别已成为人机交互的重要方式.Microsoft Azure Speech Service 提供了强大的语音转文本功能,允许开发者轻松地将语音数据转换为文本.本文将指 ...
- 获取Map中选择的要素
<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255) ...
- Qt通用方法及类库2
函数名 //初始化数据库 static void initDb(const QString &dbName); //初始化文件,不存在则拷贝 static void initFile(cons ...
- Qt编写安防视频监控系统31-onvif设备搜索
一.前言 做视频监控系统,绕不过onvif这玩意,这玩意主要就是为了统一一个大概的标准,能够对各个厂家的监控设备进行常用的一些操作,比如搜索.获取信息.云台控制.事件订阅.抓拍图片等,如果没有这个规范 ...
- LetsTalk_Android中引导用户加入白名单图-2
=================================================================== ================================ ...
- Python串口实现dk-51e1单相交直流标准源通信
Python实现dk-51e1单相交直流标准源RS232通信 使用RS232,信号源DK51e1的协议帧格式如下: 注意点 配置串口波特率为115200 Check异或和不需要加上第一个0x81的字段 ...
- unordered_map比map慢?
先说结论:unordered_map不维护键的顺序,因此不能按顺序访问元素,因此如果你需要遍历表时若选用unordered_map就肯定比map慢 1. 数据结构与底层实现 unordered_map ...
- c# 更改快捷方式文件图标
c# 更改快捷方式文件图标c# 更改快捷方式文件图标c# 更改快捷方式文件图标c# 更改快捷方式文件图标c# 更改快捷方式文件图标c# 更改快捷方式文件图标c# 更改快捷方式文件图标c# 更改快捷方式 ...
- Linux 运维必备 150 个命令汇总
地址:https://www.linuxcool.com 线上查询及帮助命令 man:全拼manual,用来查看系统中自带的各种参考手册. help:用于显示shell内部命令的帮助信息. 文件和目录 ...