这种题目。。。哎。。智商不够用啊。。由于输入只有一个x的值,所以电路无论多复杂,最终结果只有1,0,x或!x(所以可以这样理解,当电路的输出与x相关时,原电路一定可以等效为输入序列只有一个x其余均为0/1的情况)。取x为0与x为1,如果电路的输出结果相同,那么电路的输出结果一定是常数,那么随便输出一串0,1就行。。否则,由前面的讨论我们只需要找到那个填上x的位置,从全为0的输入开始,对于全为0的输入记其输出为a。每次将输入序列的第一个0替换为1。直到找到一个k使得输入序列的前k个数均为1时,该序列的输出结果不是a为止,那么我们的输入序列可以简化为111...1(k-1个1)x00000...(后面全是0)。因为对于全为1的输入序列,其输出不等于a所以符合条件的k一定存在,即这样的算法一定会给出答案。关于k的找法用二分,详见代码。
AC代码如下:(参考了编程。。毕竟我真的不会写这题。。)
#include <cstdio>
using namespace std;
int n,m,inp1[200005],inp2[200005],out[2000005];
int calculate(int k) //当输入序列的前k个数均为1时求电路的输出
{
for(int i=1;i<=m;i++)
{
int a,b;
if(inp1[i]<0)
a=(-inp1[i]<=k);
else
a=out[inp1[i]];
if(inp2[i]<0)
b=(-inp2[i]<=k);
else
b=out[inp2[i]];
out[i]=!(a&b);
}
return out[m];
}
int main(int argc, char const *argv[])
{
int T;
scanf("%d", &T);
while(T--)
{
scanf("%d %d", &n, &m);
for(int i=1;i<=m;i++)
scanf("%d %d", &inp1[i],&inp2[i]);
int x,y;
x=calculate(0);
y=calculate(n);
if(x==y)
{
for(int i=1;i<=n;i++)
printf("0");
printf("\n");
}
else
{
int L=0,R=n,mid=1; //二分查找
while(R-L>1)
{
mid=(L+R)/2;
if(calculate(mid)==x)
L=mid;
else
R=mid;
}
for(int i=1;i<=n;i++)
{
if(i<R) printf("1");
else if(i==R) printf("x");
else printf("0");
}
printf("\n");
}
}
return 0;
}