[CF1344]Piets Palette

Piet's Palette

题解

我真的感觉这道题与线性基没有什么关系,可能是蒟蒻太菜了吧,可T**M*E***非要叫我这样做,不过我还是没用线性基

这都是因为我太菜了呀!!!

话说看到这道题时我是一直****************的。还是先来讲做法吧,别问蒟蒻怎么想到的。

因为它要让我们通过给出的方案来得到一个合法的方案数,而给的方法很像方程,所以我们可以利用高斯消元来解决这道题。

可到底应该列方程呢,这就是一个天大的问题了。

我们可以通过向量来表示

R为\begin{bmatrix} 1\\ 0 \end{bmatrix},Y为\begin{bmatrix} 0\\1 \end{bmatrix},B为\begin{bmatrix} 1\\1 \end{bmatrix},而W为\begin{bmatrix} 0\\ 0 \end{bmatrix}

然后就会惊奇地发现,mix的操作可以用它们表示出来,也就是在二进制下相加。

每一个mix操作可以变为两个方程,毕竟向量有两个值。我们就对于所有得到的方程进行高斯消元,之后就可以求出每个位置上的值了。而这方程是一个只有0与1的异或方程,毕竟每一个颜色都是用只包含0,1的向量来表示的,空间有点大,可以用bitset来进行存储。

至于其他的置换操作,我们可以把每个位置上的原矩阵通过矩阵乘法来对原系数进行操作,来置换最后的答案值。

而这些置换操作等价于一些2*2的矩阵,分别是

RY为\begin{bmatrix} 0 &1 \\ 1 &0 \end{bmatrix},YB为\begin{bmatrix} 1 &1 \\ 0 &1 \end{bmatrix},RB为\begin{bmatrix} 1 &0 \\ 1 & 1 \end{bmatrix}

如此一来,就能构造出2n\cdot 2m的异或方程组,但可能会有n> m的情况,这时候我们只需要将求不出来的项设为0即可,因为0时是一定满足当前方程组的。

源码

真的难打,你什么都没看见

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>
using namespace std;
#define MAXN 1005
typedef long long LL;
const int MAXM=60;
typedef pair<int,int> pii;
template<typename _T>
void read(_T &x){
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
	x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
struct Martix{
	int c[2][2];
	Martix(){memset(c,0,sizeof(c));}
	Martix operator * (const Martix &rhs)const{
		Martix res;
		for(int i=0;i<2;i++)
			for(int k=0;k<2;k++)
				for(int j=0;j<2;j++)
					res.c[i][j]^=(c[i][k]&rhs.c[k][j]);
		return res;
	}
	void print(){
		puts("");
		for(int i=0;i<2;i++){
			for(int j=0;j<2;j++)
				printf("%lld ",c[i][j]);
			puts("");	
		}
		puts("");
	}
}I,A[4],a[MAXN],B,Y,R,W,T;
namespace Gauss{
	bitset<MAXN*2> a[MAXN*2];
	int pos[MAXN*2],sol[MAXN*2],n,m;
	bool work(){
		for(int i=1,j=1;i<=m&&j<=n;i++,j++){
			while(j<=n){
				bool fg=false;
				for(int k=i;k<=m;k++)if(a[k][j]){swap(a[i],a[k]);fg=1;break;}
				if(fg)break;j++;
			}
			if(j>n)break;pos[i]=j;
			for(int k=i+1;k<=m;k++)if(a[k][j])a[k]^=a[i];
		}
		for(int i=m;i>0;i--)
			if(pos[i]){
				int tmp=a[i][n+1];
				for(int j=pos[i]+1;j<=n;j++)
					tmp^=(a[i][j]&sol[j]);
				sol[pos[i]]=tmp;
			}
		for(int i=1;i<=m;i++){
			int tmp=a[i][n+1];
			for(int j=pos[i];j<=n;j++)
				tmp^=(a[i][j]&sol[j]);
			if(tmp)return false;
		}
		return true;
	}
	void print(){
		for(int i=1;i<=m;i++){
			for(int j=1;j<=n+1;j++)
				if(a[i][j])putchar('1');
				else putchar('0');
			puts("");
		}
	}
}
int turn(char x){return x=='R'?1:(x=='Y'?2:(x=='B'?3:0));}
int n,k;
signed main(){
	read(n);read(k);
	I.c[0][0]=I.c[1][1]=1;
	A[1].c[0][0]=A[1].c[0][1]=A[1].c[1][1]=1;
	A[2].c[0][0]=A[2].c[1][0]=A[2].c[1][1]=1;
	A[3].c[0][1]=A[3].c[1][0]=1;
	//B.c[0][0]=B.c[0][1]=1;
	//Y.c[0][1]=R.c[0][0]=1;
	//T=A[1]*A[2];T.print();
	for(int i=1;i<=n;i++)a[i]=I;Gauss::n=n*2;
	for(int i=1;i<=k;i++){
		char opt[15];scanf("%s",opt);
		if(opt[0]=='m'){
			Gauss::m+=2;int m;read(m);
			for(int j=1;j<=m;j++){
				int x;read(x);
				Gauss::a[Gauss::m-1][2*x-1]=a[x].c[0][0];
				Gauss::a[Gauss::m-1][2*x]=a[x].c[0][1];
				Gauss::a[Gauss::m][2*x-1]=a[x].c[1][0];
				Gauss::a[Gauss::m][2*x]=a[x].c[1][1];
			}
			scanf("%s",opt);int c=turn(opt[0]);
			Gauss::a[Gauss::m-1][n<<1|1]=c&1;
			Gauss::a[Gauss::m][n<<1|1]=c>>1;
		}
		else{
			int c=turn(opt[0])^turn(opt[1]),m;read(m);
			while(m--){int x;read(x);a[x]=A[c]*a[x];}
		}
	}
	Gauss::print();
	if(!Gauss::work()){puts("NO");return 0;}
	puts("YES");
	for(int i=1;i<=n;i++){
		int x=(Gauss::sol[i*2]<<1)|Gauss::sol[i*2-1];
		printf("%c",x==1?'R':(x==2?'Y':(x==3?'B':'.')));
	} 
	return 0;
}

谢谢!!!

原创文章 124 获赞 167 访问量 1万+

猜你喜欢

转载自blog.csdn.net/Tan_tan_tann/article/details/106123500
今日推荐