题解:[JOI Open 2021] 杂交 / Crossing

题目传送门

题意分析

钦定 \(\text{J}=0,\text{O}=1,\text{I}=2\)\(c_1,c_2\) 得到 \(c_3\) 运算规则显然是模 \(3\) 意义下的,可以发现:

\[c_1+c_2\equiv-c_3\pmod3 \]

也就是说 \(c_3=(6-c_1-c_2)\bmod3\),之后就可以 \(\mathcal O(n)\) 计算 cross 操作。

记初始资源库里的串为 \(a,b,c\),各项之间独立,若干次 cross 操作后 \(a_i,b_i,c_i\) 产生的项一定可以表述为 \(k_1a_i+k_2b_i+k_3c_i\),且 \(0\leq k_1,k_2,k_3\leq2\)。由此想到有用的串不多。

cross 操作答案与顺序无关,满足交换律,但不满足结合律。

有用的串只有:

\[a,b,c,a\operatorname{cross}b,a\operatorname{cross}c,a\operatorname{cross}(b\operatorname{cross}c),b\operatorname{cross}c,b\operatorname{cross}(a\operatorname{cross}c) \]

因为 \(a\operatorname{cross}a\) 这种操作没什么用,可以发现 \(a_i\)\(a_i\) 操作后还是 \(a_i\)

之后就考虑区间修改再快速判断相等。

线段树配合哈希维护即可。

据说卡哈希,但还好我一直写的都是异或 + 随机数实现的哈希。

AC 代码

//#include<bits/stdc++.h>
#include<algorithm> 
#include<iostream>
#include<cstring>
#include<iomanip>
#include<cstdio>
#include<string>
#include<vector>
#include<cmath>
#include<ctime>
#include<deque>
#include<queue>
#include<stack>
#include<list>
#include<random>
using namespace std;
constexpr const int N=2e5,V=9;
mt19937 Rand(time(0));
int n,a[N+1],b[N+1],c[N+1],t0[N+1],ans[V+1],w[N+1][3],preW[N+1][3];
int joi(char ch){
	switch(ch){
		case 'J':
			return 0;
		case 'O':
			return 1;
		case 'I':
			return 2;
	}
}
int calc(int a[]){
	int ans=0;
	for(int i=1;i<=n;i++){
		ans^=w[i][a[i]];
	}
	return ans;
}
int cross(int a[],int b[]){
	static int c[N+1];
	for(int i=1;i<=n;i++){
		c[i]=(6-a[i]-b[i])%3;
	}
	return calc(c);
}
int* cross(int a[],int b[],int c[]){
	for(int i=1;i<=n;i++){
		c[i]=(6-a[i]-b[i])%3;
	}
	return c;
}
void pre(){
	static int d[N+1];
	ans[1]=cross(a,b);
	ans[2]=cross(a,cross(b,c,d));
	ans[3]=cross(a,c);
	ans[4]=cross(cross(a,b,d),c);
	ans[5]=cross(b,c);
	ans[6]=cross(cross(a,c,d),b);
	ans[7]=calc(a);
	ans[8]=calc(b);
	ans[9]=calc(c);
}
struct segTree{
	struct node{
		int l,r;
		int value,tag;
		
		int size(){
			return r-l+1;
		}
	}t[N<<2|1];
	
	void up(int p){
		t[p].value=t[p<<1].value^t[p<<1|1].value;
	}
	void build(int p,int l,int r){
		t[p]={l,r};
		t[p].tag=-1;
		if(l==r){
			t[p].value=w[l][t0[l]];
			return;
		}
		int mid=l+r>>1;
		build(p<<1,l,mid);
		build(p<<1|1,mid+1,r);
		up(p);
	}
	void down(int p){
		if(t[p].tag!=-1){
			t[p<<1].value=preW[t[p<<1].r][t[p].tag]^preW[t[p<<1].l-1][t[p].tag];
			t[p<<1].tag=t[p].tag;
			t[p<<1|1].value=preW[t[p<<1|1].r][t[p].tag]^preW[t[p<<1|1].l-1][t[p].tag];
			t[p<<1|1].tag=t[p].tag;
			t[p].tag=-1;
		}
	}
	void set(int p,int l,int r,int c){
		if(l<=t[p].l&&t[p].r<=r){
			t[p].value=preW[t[p].r][c]^preW[t[p].l-1][c];
			t[p].tag=c;
			return;
		}
		down(p);
		if(l<=t[p<<1].r){
			set(p<<1,l,r,c);
		}
		if(t[p<<1|1].l<=r){
			set(p<<1|1,l,r,c);
		}
		up(p);
	}
	int query(){
		return t[1].value;
	}
}t;
bool query(int l,int r,int c0){
	if(1<=l&&r<=n){
		t.set(1,l,r,c0);
	}
	for(int i=1;i<=V;i++){
		if(t.query()==ans[i]){
			return true;
		}
	}
	return false;
}
int main(){
	/*freopen("test.in","r",stdin);
	freopen("test.out","w",stdout);*/
	
	ios::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);
	
	cin>>n;
	for(int i=1;i<=n;i++){
		char ch;
		cin>>ch;
		a[i]=joi(ch);
	}
	for(int i=1;i<=n;i++){
		char ch;
		cin>>ch;
		b[i]=joi(ch);
	}
	for(int i=1;i<=n;i++){
		char ch;
		cin>>ch;
		c[i]=joi(ch);
	}
	for(int i=1;i<=n;i++){
		w[i][0]=Rand();
		preW[i][0]=preW[i-1][0]^w[i][0];
		w[i][1]=Rand()
		preW[i][1]=preW[i-1][1]^w[i][1];
		w[i][2]=Rand(;
		preW[i][2]=preW[i-1][2]^w[i][2];
	}
	pre();
	int q;
	cin>>q;
	for(int i=1;i<=n;i++){
		char ch;
		cin>>ch;
		t0[i]=joi(ch);
	}
	t.build(1,1,n);
	cout<<(query(0,0,0)?"Yes":"No")<<'\n';
	while(q--){
		int l,r;
		char ch;
		cin>>l>>r>>ch;
		cout<<(query(l,r,joi(ch))?"Yes":"No")<<'\n';
	}
	
	cout.flush(); 
	
	/*fclose(stdin);
	fclose(stdout);*/
	return 0;
}
/*
4
JOJO
JJOI
OJOO
0
OIII

Yes
*/
posted @ 2026-07-17 16:32  TH911  阅读(5)  评论(0)    收藏  举报