洛谷 U141384 电路

洛谷 U141384 电路

洛谷传送门

题目背景

SeawaySeawa**y是热爱学习的好孩子。

有一天,SeawaySeawa**y正在向他的物理老师LSPLSP讨教物理。LL老师向他介绍了一种神奇的电路,逻辑电路:

LL老师说:逻辑电路是一种离散信号的传递和处理、以二进制为原理、实现数字信号逻辑运算和操作的电路。分组合逻辑电路时序逻辑电路。前者由最基本的“与门”电路、“或门”电路和“非门”电路组成,其输出值仅依赖于其输入变量的当前值,与输入变量的过去值无关——即不具记忆和存储功能;后者也由上述基本逻辑门电路组成,但存在反馈回路——它的输出值不仅依赖于输入变量的当前值,也依赖于输入变量的过去值。逻辑电路广泛应用于计算机、数字控制、通信、自动化和仪表等方面。

比如,下图就是一张逻辑电路的电路图:

img

SeawaySeawa**y瞪大了眼睛:太奇妙啦!突然,他的脑中灵光一闪,想到了一个问题......

题目描述

SeawaySeawa**y把任何一套逻辑电路都归为五种基本元件和若干导线。其中,五种基本原件分别是与门(\text{AND}AND),或门(\text{OR}OR),非门(\text{NOT}NOT),异或门(\text{XOR}XOR)和终端(\text{IN}IN)。除终端之外,每个原件有两个入端和一个出端,其作用是把两个入端进入的信号进行逻辑运算,逻辑运算种类和原件种类相同,然后将结果信号输出给出端。信号只有0/10/1两种。终端比较特殊,它自带一种可变信号且只有一个出端,显然,它会把这个信号直接输出给出端。

按照题目背景的描述,显然地,按这种形式、用原件和导线组合成的逻辑电路属于组合逻辑电路。我们限制:整个电路最终只能有一个出端。显然地,如果所有终端的信号被唯一确定,那么整个电路的出端所输出的信号也会被唯一确定。

现在,SeawaySeawa**y的问题是:对于一个给定的组合逻辑电路,每次只改变其中的一个终端的自带信号后,整个电路的出端信号会输出什么信号。

输入格式

从文件circuit.incircuit.i**n中读入数据。

第一行包含一个整数NN。表示原件数量。原件从1-N1−N编号。我们令11号原件的出端为整个电路的出端。数据保证11号原件不会为终端,所有原件都在同一个逻辑电路中。

接下来NN行,每一行描述一个原件,描述规则如下:

首先是一个字符串optopt,为\text{AND,OR,XOR,NOT,IN}AND,OR,XOR,NOT,IN,表示原件种类。

如果原件不为终端,那么接下来两个整数s1,s2s1,s2,表示当前原件的入端所链接的原件编号。

如果原件为终端,那么接下来一个整数p\in[0,1]p∈[0,1],表示终端的初始自带信号种类。

输出格式

输出到文件circuit.outcircuit.out中。

一个0/10/1串,从左到右的每一位表示按编号顺序依次改变每个终端的自带信号后,终端输出信号的种类。


命题背景:

这题我觉得差不多真够我吹一阵子。

题面出奇的精美,爱了爱了。

反差萌->学弟。


题解:

好像还是给了30pts的暴力吧。\(O(n^2)\)的。听学长说优化优化暴力可以打\(O(n^2/32)\)的,好像是用bitset玄学优化优化,不太懂。

然后70分是随机数据,不会出现链卡你,所以这时枚举路径,跑不满\(O(n\log n)\),非常可观。

不难发现:如果一个叶子节点被更改影响到,那么可以肯定的是,这个叶子节点到根节点的链(这个链是唯一的)的所有值都会被取反。那么我们来看这些操作,当操作为非或者异或的时候,那么这个节点的值会被取反(任意一个儿子被修改即可)。反之,如果操作为与或或,必须两个儿子的值都被修改,才能被取反。 但是这道题一次只修改一个叶子节点,所以不存在这种情况。

所以在每个点打一个标记数组,表示这个点会不会随着儿子节点的权值变化而变化,然后维护一个标记数组,从上到下深搜表示这个变化会不会使得父亲节点有变化。然后下传这个标记,最后输出对应的答案就好,整个复杂度是\(O(n)\)的。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn=1e6+10;
int n,ans[maxn],opt[maxn],son[maxn][2],val[maxn];
bool v[maxn];
int turn(char s[])
{
    if(s[0]=='I') 
        return 1;
    if(s[0]=='N') 
        return 2;
    if(s[0]=='O') 
        return 3;
    if(s[0]=='A') 
        return 4;
    if(s[0]=='X') 
        return 5;
}
int dfs1(int u)
{
    if(opt[u]==1) 
        return val[u];
    if(opt[u]==2) 
        return(val[u]=!dfs1(son[u][0]));
    if(opt[u]==3) 
        return(val[u]=(dfs1(son[u][0])|dfs1(son[u][1])));
    if(opt[u]==4) 
        return(val[u]=(dfs1(son[u][0])&dfs1(son[u][1])));
    if(opt[u]==5) 
        return(val[u]=(dfs1(son[u][0])^dfs1(son[u][1])));
}
void dfs2(int u)
{
    if(v[u]==0) 
        v[son[u][0]]=v[son[u][1]]=0;
    else
    {
        switch(opt[u])
        {
            case 2:
                v[son[u][0]]=1;
                break;
            case 3:
                if(val[son[u][0]]) 
                    v[son[u][1]]=0;
                else 
                    v[son[u][1]]=1;
                if(val[son[u][1]]) 
                    v[son[u][0]]=0;
                else 
                    v[son[u][0]]=1;
                break;
            case 4:
                if(!val[son[u][0]])
                    v[son[u][1]]=0;
                else 
                    v[son[u][1]]=1;
                if(!val[son[u][1]]) 
                    v[son[u][0]]=0;
                else 
                    v[son[u][0]]=1;
                break;
            case 5:
                v[son[u][0]]=v[son[u][1]]=1; 
                break;
        }
    }
    v[0]=0;
    if(son[u][0]) 
        dfs2(son[u][0]);
    if(son[u][1]) 
        dfs2(son[u][1]);
}
int main()
{
    memset(v,1,sizeof(v));
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        char s[10]; 
        scanf("%s",s);
        opt[i]=turn(s);
        if(opt[i]==1)
            scanf("%d",&val[i]);
        else if(opt[i]==2) 
            scanf("%d",&son[i][0]);
        else 
            scanf("%d%d",&son[i][0],&son[i][1]);
    }
    dfs1(1);
    v[1]=1;
    dfs2(1);
    for(int i=1;i<=n;i++) 
        if(opt[i]==1)  
            printf("%d",val[1]^v[i]);
    return 0;
}
posted @ 2020-12-01 13:29  Seaway-Fu  阅读(183)  评论(0编辑  收藏  举报