把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

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

点此看题面

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

简单分类讨论

如果一个变量\(x_i\)在三组中取值相同(假设都为真),只要用一个表达式\(!x_i\rightarrow 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('\n');
	}
}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\n",tot),clear(),0;
}
posted @ 2021-06-18 09:19  TheLostWeak  阅读(86)  评论(0编辑  收藏  举报