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