题目
思路
1._对于输入不同的x,电路最后的输出无非只有4种情况,常数0,常数1,x,非x。
- 常数时,直接判断x=0,x=1输出是否相同。相同的话,x对电路无影响,直接输出全0或全1即可。
- 与x有关时,即当x取0时,电路是一种结果。x取1时,电路是另一种结果。
2._**通过x=0和x=1输出不同**,判定x所在位置。
设x=0时输出0,x=1时输出1
0 0 0 0 -> 0
1 1 1 1->1
从0000开始,依次填1,当输出变成1时,就是所求x的位置。
1 0 0 0 -> 0
1 1 0 0 -> 1
(证明)
由于初始设,必然有一个过渡态满足上述情况。并且此过渡态只有一个,也证明了x最少为1个。
代码
#include <cstdio>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int maxn = 200000 + 1000;
int n, m; // n:输入数,m:总gate数
struct gate { // 适当时候使用结构体,可以减少变量的分散,从而提高代码可读性
int a, b, o; // a,b输入,o输出
}gates[maxn];
int output(int k) { // 返回当输入是000...111(有k个0时)的结果
for (int i = 1; i <= m; i++) {
int a = gates[i].a;
int b = gates[i].b;
int va = a<0 ? -a>k : gates[a].o;
int vb = b<0 ? -b>k : gates[b].o;
// c++中 ? : 结构的使用
// 如vb的赋值,若b<0,返回-b>k,否则返回gates[b].o
gates[i].o = !(va && vb);
// 就是当va,va全为1的时候,为0
}
return gates[m].o;
}
// 返回这样的k值
// 1.output(k) = output(n) = vn
// 2.output(k-1) = output(0)
int solve(int vn) {
int L = 1, R = n;
while (L < R) {
int M = L + (R - L) / 2;
if (output(M) == vn) R = M;
else L = M + 1;
}
return L;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d%d", &n, &m);
for (int i = 1; i <= m; i++)
scanf("%d%d", &gates[i].a, &gates[i].b);
int v0 = output(0);
int vn = output(n);
if (v0 == vn) {
for (int i = 1; i <= n; i++) printf("1");
}
else {
int x = solve(vn);
for (int i = 1; i < x; i++) printf("0");
printf("x");
for (int i = x + 1; i <= n; i++) printf("1");
}
printf("\n");
}
return 0;
}
码农小技巧
1.适当时候使用结构体,可以减少变量的分散,从而提高代码可读性。
struct gate {
int a, b, o; // a,b输入,o输出
}gates[maxn];
而非
pair<int, int> G[maxn], firstrow[maxn];
int n, m, frnum, output[maxn], input[maxn];
2.c++中 ? : 结构的使用
int vb = b<0 ? -b>k : gates[b].o;
// 如vb的赋值,若b<0,返回-b>k,否则返回gates[b].o
感受
LRJ大佬真的好强。。。写出来的代码好看到无法自拔。。
我自己写这道题的代码106行还各种巨长还TLE,LRJ大佬代码简洁无比。。
都要爱上他的代码了。。。。