题解:[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
*/

浙公网安备 33010602011771号