
本题需要看出最终总能将输入个数减为1个。
由于输入只是x,所以这个电路的功能只有4种情况。
先验证前两种,x分别取0和1,若输出都为0,则为第一种;若输出都为1,则为第二种。如果是这两种的一个,则输入全为0或全为1即可。
若两种都不是,则先将所有输入x都设为0,从第1个开始改成1,注意改完之后不要再改回来。当改到某一个x为1时,输出变了。则说明该位置可以控制整个电路的输出,则把该位置设为x,其它已经改为1的就还是1,没改的就还是0.
这么做是正确的,因为最终整个电路总会随着设为x的那个位置变化而变化,且电路功能不会改变。因为改到x位置之前一位时,电路输出与全为0时输出相同,就是说x位置为0时与所有输入为0时输出相同,而x为1时与所有输入为1时输出相同。
当然,直接找的话会超时。所以二分。
本题二分是可行的。因为当所有输入为1时,答案一定与所有输入为0时不同。所以我们要找的两种答案的分界点一定是存在的。即使随着1的个数过多,输出可能又会变成输入为0时结果,但它与输入全为1时之间一定还有一个分界点,可能这个分界点不是1的个数最小的情况。但由于题中未要求1的个数最少,所以也是正确的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
| #include<bits/stdc++.h> using namespace std; #define ll long long const int maxn = 1e6 + 10; int t, n, m; int ans[2], a[maxn]; struct X { int in1, in2, out; }g[maxn]; int nand(int x, int y) { return (x&y) ^ 1; } void cal(int j) { int u, v; if (g[j].in1 < 0)u = a[-g[j].in1]; else u = g[g[j].in1].out; if (g[j].in2 < 0)v = a[-g[j].in2]; else v = g[g[j].in2].out; g[j].out = nand(u, v); } int main() { scanf("%d", &t); while (t--) { scanf("%d%d", &n, &m); for (int i = 1; i <= m; i++) { scanf("%d%d", &g[i].in1, &g[i].in2); } for (int i = 0; i < 2; i++) { fill(a + 1, a + n + 1, i); for (int j = 1; j <= m; j++) { cal(j); } ans[i] = g[m].out; } if (ans[0] == ans[1]) { for (int i = 1; i <= n; i++)printf("1"); printf("\n"); } else { memset(a, 0, sizeof(a)); bool flg = 0; int L = 1, R = n, mid; while(L<R){ mid = ((L + R) >> 1); memset(a, 0, sizeof(a)); fill(a + 1, a + mid + 1, 1); for (int j = 1; j <= m; j++) { cal(j); } if (g[m].out == ans[1]) { R = mid; } else L = mid + 1; } for (int i = 1; i <= n; i++) { if (i == L)printf("x"); else printf("%d", a[i]); } printf("\n"); } } return 0; }
|