[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;
}

謝謝!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章