【洛谷1745】[CERC2016] Lost Logic(构造题)

点此看题面

  • 一个表达式形如((!)x_i ightarrow(!)x_j),表示(x_i)为真(假)时(x_j)一定为真(假)。
  • 给定(n)(01)变量的三组取值,要求构造若干表达式使得有且仅有这三组解,或判断无法构造。
  • (nle50),表达式个数不能超过(500)

简单分类讨论

如果一个变量(x_i)在三组中取值相同(假设都为真),只要用一个表达式(!x_i ightarrow x_i)即可满足条件。

否则,它必然会在某一组中取值与另两组不同,假设是在第(t)组。

对于(t)相同的两个变量(x_i,x_j),确定了(x_i)也就确定了(x_j),可以直接利用两个表达式描述这层关系。

因此最后只需保留(t)不同的变量,此时我们只能在一个变量取到它的第(t)组取值时才能确定其他变量的取值。

实际上,当三种变量都存在的时候是无法构造的,否则显然可行。

代码:(O(n))

#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 50
using namespace std;
int n,p[3],a[3][N+5];
namespace Printer
{
	#define pc(x) (*C++=x)
	#define write(x) (x>9&&pc(x/10+48),pc(x%10+48)) 
	int tot;char FO[100000],*C=FO;I void clear() {fwrite(FO,1,C-FO,stdout);}
	I void print(CI x,CI p,CI y,CI q)//x=p -> y=q
	{
		++tot,!p&&pc('!'),pc('x'),write(x),pc(' '),pc('-'),pc('>'),pc(' '),!q&&pc('!'),pc('x'),write(y),pc('
');
	}
}using namespace Printer;
int main()
{
	RI i,j,k;for(scanf("%d",&n),k=0;k<=2;++k) for(i=1;i<=n;++i) scanf("%d",a[k]+i);
	RI t;for(i=1;i<=n;++i)
	{
		if(a[0][i]==a[1][i]&&a[0][i]==a[2][i]) {print(i,a[0][i]^1,i,a[0][i]);continue;}//在三组中取值相同
		if(!p[t=a[0][i]^a[1][i]?(a[0][i]^a[2][i]?0:1):2]) {p[t]=i;continue;}//尚无这一种变量,记录下来
		print(p[t],a[t][p[t]],i,a[t][i]),print(p[t],a[t][p[t]]^1,i,a[t][i]^1);//可以直接确定
	}
	if(p[0]&&p[1]&&p[2]) return puts("-1"),0;//如果三种变量都存在则无解
	for(i=0;i<=2;++i) for(j=0;j<=2;++j) i^j&&p[i]&&p[j]&&(print(p[i],a[i][p[i]],p[j],a[i][p[j]]),0);//只有取到对应组取值时才能确定另一类变量
	return printf("%d
",tot),clear(),0;
}
败得义无反顾,弱得一无是处
原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu1745.html