Piet's Palette
題解
我真的感覺這道題與線性基沒有什麼關係,可能是蒟蒻太菜了吧,可T**M*E***非要叫我這樣做,不過我還是沒用線性基
這都是因爲我太菜了呀!!!
話說看到這道題時我是一直****************的。還是先來講做法吧,別問蒟蒻怎麼想到的。
因爲它要讓我們通過給出的方案來得到一個合法的方案數,而給的方法很像方程,所以我們可以利用高斯消元來解決這道題。
可到底應該列方程呢,這就是一個天大的問題了。
我們可以通過向量來表示
R爲,Y爲
,B爲
,而W爲
。
然後就會驚奇地發現,mix的操作可以用它們表示出來,也就是在二進制下相加。
每一個mix操作可以變爲兩個方程,畢竟向量有兩個值。我們就對於所有得到的方程進行高斯消元,之後就可以求出每個位置上的值了。而這方程是一個只有0與1的異或方程,畢竟每一個顏色都是用只包含0,1的向量來表示的,空間有點大,可以用bitset來進行存儲。
至於其他的置換操作,我們可以把每個位置上的原矩陣通過矩陣乘法來對原係數進行操作,來置換最後的答案值。
而這些置換操作等價於一些2*2的矩陣,分別是
RY爲,YB爲
,RB爲
。
如此一來,就能構造出的異或方程組,但可能會有
的情況,這時候我們只需要將求不出來的項設爲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;
}