CF1344F Piet's Palette 题解

CF1344F Piet's Palette

我们发现,如果两项颜色相同,则把两项都删去,这很符合异或的性质。再结合后面一条两项颜色不同,将这两项替换为与这两种颜色不同的颜色,我们发现需要找到三个数 a,b,c 来代表三种颜色,并且满足 ab=c,ac=b,bc=a。当 a=1,b=2,c=3 时,刚好满足条件。自然,0 就代表了白色与空位。

接下来,我们考虑如何维护另外三种操作。每一个位置的颜色需要两个二进制位来存储,我们把每一个位置的两个二进制位拆成 aibi,其中 ai 表示低位,bi 表示高位。我们令 1 对应红色,2 对应黄色,3 对应蓝色。

对于 RY 操作,我们只需要把子序列内 aibi 交换,就把所有 R 变为 Y,所有 Y 变为 RB 和空位置不变。

修改前颜色 修改前编号 修改后编号 修改后颜色
R 01 10 Y
Y 10 01 R
B 11 11 B
. 00 00 .

对于 RB 操作,我们只需要把子序列内 bi 改为 aibi,就把所有 R 变为 B,所有 B 变为 RY 和空位置不变。

修改前颜色 修改前编号 修改后编号 修改后颜色
R 01 11 B
Y 10 10 Y
B 11 01 R
. 00 00 .

对于 YB 操作,我们只需要把子序列内 ai 改为 aibi,就把所有 Y 变为 B,所有 B 变为 YR 和空位置不变。

修改前颜色 修改前编号 修改后编号 修改后颜色
R 01 01 R
Y 10 11 B
B 11 10 Y
. 00 00 .

我们需要对于每个位置维护两个变量,saisbi,分别表示低位是 ai,bi,aibi 中的哪一个和高位是 ai,bi,aibi 中的哪一个。我们利用位运算,来记录构成这一位的答案中是否存在 aibi

对于每一个 mix 操作,把子序列中的低位和高位依次异或,结果要等于给出的混合结果对应的编号的低位和高位,我们就能得到两个等式。于是,我们就得到了一个异或方程组。直接使用高斯消元算法求解即可。

#include <bits/stdc++.h>
using namespace std;
long long n,k,now[4100],y[4100],sa[4100],sb[4100],cnt=0;
bool a[4100][4100],b[4100],ans[4100];
string op;
void ry()
{
	long long m=0,now=0;
	cin>>m;
	for(int i=1;i<=m;i++)
	    {
	    cin>>now;
	    swap(sa[now],sb[now]);
	    }
}

void rb()
{
	long long m=0,now=0;
	cin>>m;
	for(int i=1;i<=m;i++)
		{
		cin>>now;
		sb[now]=sa[now]^sb[now];
	    }
}

void yb()
{
	long long m=0,now=0;
	cin>>m;
	for(int i=1;i<=m;i++)
	    {
	    cin>>now;
	    sa[now]=sa[now]^sb[now];
	    }
}

void mix()
{
	long long m=0,id=0;
	char col=0;
	cin>>m;
	for(int i=1;i<=m;i++)cin>>now[i];
	cin>>col;
	if(col=='W')id=0;
	if(col=='R')id=1;
	if(col=='Y')id=2;
	if(col=='B')id=3;
	cnt++,b[cnt]=id&1;
	for(int i=1;i<=m;i++)
	    {
	    if(sa[now[i]]&1)a[cnt][now[i]]=1;
	    if(sa[now[i]]&2)a[cnt][now[i]+n]=1;
	    }
	cnt++,b[cnt]=(id>>1)&1;
	for(int i=1;i<=m;i++)
	    {
	    if(sb[now[i]]&1)a[cnt][now[i]]=1;
	    if(sb[now[i]]&2)a[cnt][now[i]+n]=1;
	    }
}

bool gauss()
{
	long long now=1,res=0;
    for(int i=1;i<=n*2;i++)
        {
        long long mx=now;
        for(int j=now;j<=cnt;j++)
            if(a[j][i]!=0)
               {
			   mx=j,res=max(res,mx);
			   break;
		       }
        if(a[mx][i]==0)continue;
        if(now!=mx)
           {
           for(int j=1;j<=n*2;j++)swap(a[now][j],a[mx][j]);
           swap(b[now],b[mx]);
           }
        for(int j=now+1;j<=cnt;j++)
            if(a[j][i]==1)
	            {
	                b[j]^=b[now];
	                for(int k=i;k<=n*2;k++)a[j][k]^=a[now][k];
	            }
	    y[now]=i;
	    now++;
		}
	for(int i=now;i<=cnt;i++)
	    if(b[i])return 0;
    return 1;
}

void print(long long p)
{
	if(ans[p]==0&&ans[p+n]==0)printf(".");
	if(ans[p]==1&&ans[p+n]==0)printf("R");
	if(ans[p]==0&&ans[p+n]==1)printf("Y");
	if(ans[p]==1&&ans[p+n]==1)printf("B");
}

int main()
{
    cin>>n>>k;
    for(int i=1;i<=n;i++)sa[i]=1,sb[i]=2;
    for(int i=1;i<=k;i++)
        {
        	cin>>op;
        	if(op=="RY")ry();
        	else if(op=="RB")rb();
        	else if(op=="YB")yb();
        	else if(op=="mix")mix();
		}
	if(!gauss())printf("NO\n");
	else
	   {
	   	printf("YES\n");
	   	ans[y[n*2]]=b[n*2];
	   	for(int i=n*2-1;i>=1;i--)
	        {
	        ans[y[i]]=b[i];
	        for(int j=n*2;j>y[i];j--)
			    if(a[i][j])ans[y[i]]^=ans[j];
	        }
	    for(int i=1;i<=n;i++)print(i);
	    printf("\n");
	   }
	return 0;
}
posted @   w9095  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示