CF1344F Piet's Palette【线性代数】

设一个 \(\texttt{RYB}\) 字符串混合的结果为做如下操作直到字符串长度 \(\le 1\):若开头两个字符不同,将其替换为一个与这两个字符都不同的字符;否则将这两项删去。

若最终序列长度 \(=1\) 则结果即为唯一的字符,否则为 \(\texttt W\)

有一个长为 \(n\) 的字符串,其中有些位置是空的,\(k\) 次操作:

  • \(\texttt{mix m j_1 j_2 }\cdots\texttt{ j_m c}\):将第 \(j_1,\cdots,j_m\) 个字符按顺序混合,得到字符 \(c\)
  • \(\texttt{RY/RB/YB m j_1 j_2 }\cdots\texttt{ j_m}\):将第 \(j_1,\cdots,j_m\) 个字符交换 \(\texttt{RY/RB/YB}\)

构造出合法的原字符串。需判断无解。

\(n,k\le 10^3\)


很容易发现 \(\texttt{W/.RYB}\) 代表 \(0,1,2,3\),混合即为异或和。然后发现不太好处理交换操作。

不容易发现交换操作是线性变换,因此我们可以把每个数拆成两个基底 \(a_i,b_i\) 的线性组合,初始时 \(a_i=1,b_i=2\),则 \(\texttt{RY/RB/YB}\) 分别是 swap(a[i],b[i])b[i] ^= a[i]a[i] ^= b[i]

然后解一个 \(2n\)\(2k\) 个方程的方程组即可,时间复杂度是三方的。

#include<bits/stdc++.h>
using namespace std;
const int N = 2003;
template<typename T>
void read(T &x){
    int ch = getchar(); x = 0;
    for(;ch < '0' || ch > '9';ch = getchar());
    for(;ch >= '0' && ch <= '9';ch = getchar()) x = x * 10 + ch - '0';
}
int n, m, k, a[N], b[N], ans[N];
bitset<N> bas[N];
void ins(bitset<N> val){
    for(int i = 0;i < (n<<1);++ i) if(val[i]){
        if(bas[i].none()){bas[i] = val; return;}
        val ^= bas[i];
    } if(val[n<<1]){puts("NO"); exit(0);}
}
int ID(char x){
    switch(x){
    case 'R': return 1;
    case 'Y': return 2;
    case 'B': return 3;
    default: return 0;
    }
}
int main(){
    read(n); read(k);
    for(int i = 0;i < n;++ i){a[i] = 1; b[i] = 2;}
    while(k --){
        char opt[4], col[2]; scanf("%s%d", opt, &m);
        if(opt[0] == 'm'){
            bitset<N> e1, e2;
            while(m --){
                int x; read(x); -- x;
                e1[x<<1] = a[x]&1; e1[x<<1|1] = a[x]>>1;
                e2[x<<1] = b[x]&1; e2[x<<1|1] = b[x]>>1;
            } scanf("%s", col);
            int id = ID(col[0]);
            e1[n<<1] = id&1; e2[n<<1] = id>>1;
            ins(e1); ins(e2);
        } else if(opt[0] == 'R' && opt[1] == 'Y'){
            while(m --){int x; read(x); -- x; swap(a[x], b[x]);}
        } else if(opt[0] == 'R' && opt[1] == 'B'){
            while(m --){int x; read(x); -- x; b[x] ^= a[x];}
        } else {
            while(m --){int x; read(x); -- x; a[x] ^= b[x];}
        }
    }
    for(int i = (n<<1)-1;~i;-- i){
        ans[i] = bas[i][n<<1];
        for(int j = i-1;~j;-- j)
            if(bas[j][i]) bas[j] ^= bas[i];
    } puts("YES");
    for(int i = 0;i < n;++ i) putchar(".RYB"[ans[i<<1]|ans[i<<1|1]<<1]);
}
posted @ 2021-04-25 20:26  mizu164  阅读(150)  评论(0编辑  收藏  举报