题解[JOI Open 2021] Crossing

Posted SharpnessV

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解[JOI Open 2021] Crossing相关的知识,希望对你有一定的参考价值。

很有意思的一道题。

不难发觉得关键还是在变化上。

我们用 \\(1,2,3\\) 表示分别表示三个字母,那么如果 \\(c_1\\neq c_2\\),则 \\(c_3 = c_1 \\oplus c_2\\),直接异或就行。

但是如果 \\(c_1=c_2\\) 根本表示不了,后面也没法做(罚坐了半个小时

考虑用 \\(0,1,2\\) 分别表示三个字母,那么我们可以发现 \\(c_3\\equiv-c_1-c_2\\pmod{3}\\)

所以杂交后得到的串 \\(S\\) 一定可以表示为 \\(aS_A+bS_B+cS_C\\),由于每一位都是模 \\(3\\) 意义下的,所以杂交所得的串不会超过 \\(27\\) 个。

我们直接写个程序爆算所有可能的 \\((a,b,c)\\),发现只有 \\(9\\) 种可能。

int f[3][3][3];
int g(int x,int y){return (6 - x - y) % 3;}
int main(){
	//int T = read();while(T--)solve();
	f[1][0][0] = f[0][0][1] = f[0][1][0] = 1;
	rep(t, 0, 100){
		rep(i, 0, 2)rep(j, 0, 2)rep(k, 0, 2)rep(x, 0, 2)rep(y, 0, 2)rep(z, 0, 2)
			f[g(i, x)][g(j, y)][g(k, z)] |= f[i][j][k] & f[x][y][z];
	}
	rep(i, 0, 2)rep(j, 0, 2)rep(k, 0, 2)if(f[i][j][k])printf("%d, ", i);el;
	rep(i, 0, 2)rep(j, 0, 2)rep(k, 0, 2)if(f[i][j][k])printf("%d, ", j);el;
	rep(i, 0, 2)rep(j, 0, 2)rep(k, 0, 2)if(f[i][j][k])printf("%d, ", k);el;
	return 0;
}

那么我们只用预处理这 \\(9\\) 个串的哈希值,然后用线段树维护 \\(T\\) 的哈希值,这道题就做完了。

/*
    Author : SharpnessV
    Right Output ! & Accepted !
*/
#include<bits/stdc++.h>
//#define int long long

#define rep(i, a, b) for(int i = (a);i <= (b);i++)
#define pre(i, a, b) for(int i = (a);i >= (b);i--)
#define rp(i, a) for(int i = 1; i <= (a); i++)
#define pr(i, a) for(int i = (a); i >= 1; i--)
#define go(i, x) for(auto i : x)

#define mp make_pair
#define pb push_back
#define pf push_front
#define fi first
#define se second
#define ze(p) memset(p, 0, sizeof(p))
#define mem(p, x) memset(p, x, sizeof(p))
#define YES puts("Yes")
#define NO puts("No")
#define si(x) (int)(x).size()
#define db cerr
#define pc putchar
#define el putchar(\'\\n\')

using namespace std;
const double eps = 1e-15, pi = 3.1415926535897932385;
typedef long long LL;
typedef pair<int,int> Pr;
//const int dx[4] = {1,0,-1,0}, dy[4] = {0,1,0,-1}, inf = 0x7fffffff;

//char buf[1<<22],*p1=buf,*p2=buf;
//#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
inline int read(){
    int x = 0;bool f = 1;char ch = getchar();
    while(!isdigit(ch))f = (\'-\' == ch ? 0 : 1), ch = getchar();
    while(isdigit(ch))x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    if(f)return x;return -x;
}
inline LL Read(){
    LL x = 0;bool f = 1;char ch = getchar();
    while(!isdigit(ch))f = (\'-\' == ch ? 0 : 1), ch = getchar();
    while(isdigit(ch))x = (x << 1) + (x << 3) + (ch ^ 48), ch = getchar();
    if(f)return x;return -x;
}
int gcd(int x,int y){return y ? gcd(y, x % y) : x;}
int lcm(int x,int y){return x / gcd(x, y) * y;}
//#define P 1000000007
//#define P 998244353
#define P 998244853
#define bas 229
inline void ad(int &x, int y){x += y; if(x >= P) x -= P;}
inline void su(int &x, int y){x -= y; if(x < 0) x += P;}
inline void cmn(int &x,int y){if(y < x) x = y;}
inline void cmx(int &x,int y){if(y > x) x = y;}
inline void cmn(LL &x, LL y){if(y < x) x = y;}
inline void cmx(LL &x, LL y){if(y > x) x = y;}

int Pow(int x, int y){
	if(y < 0)return Pow(Pow(x, P - 2), -y);
	int now = 1 ;
	for(;y;y >>= 1, x = 1LL * x * x % P)if(y & 1) now = 1LL * now * x % P;
	return now;
}
const int dx[9] = {0, 0, 0, 1, 1, 1, 2, 2, 2}, dy[9] = {0, 1, 2, 0, 1, 2, 0, 1, 2}, dz[9] = {1, 0, 2, 0, 2, 1, 2, 1, 0};
#define N 200005
char s[3][N];
inline int f(int x){if(\'J\' == x)return 0;if(\'O\' == x)return 1;return 2;}
int n, m, hs[9], pw[N], pws[N];
struct node{
	int l, r, val, tag;
}a[N << 2];
#define L a[x].l
#define R a[x].r
#define ls (x << 1)
#define rs (ls | 1)
#define S a[x].val
#define T a[x].tag
void build(int x,int l,int r){
	L = l, R = r, T = ~0;
	if(l == r)S = f(s[0][l]);
	else{
		int mid = (l + r) >> 1;
		build(ls, l, mid);
		build(rs, mid + 1, r);
		S = (1LL * a[ls].val * pw[r - mid] + a[rs].val) % P;
	}
}
void pushup(int x, int val){S = 1LL * (T = val) * pws[R - L] % P;}
void down(int x){if(~T)pushup(ls, T), pushup(rs, T), T = ~0;}
void change(int x,int l,int r,int val){
	if(L >= l && R <= r)pushup(x, val);
	else{
		down(x);int mid = (L + R) >> 1;
		if(mid >= l)change(ls, l, r, val);
		if(mid < r)change(rs, l, r, val);
		S = (1LL * a[ls].val * pw[R - mid] + a[rs].val) % P;
	}
}
void out(){rep(op, 0, 8)if(a[1].val == hs[op]){YES;return ;}NO;}
int main(){
	//int T = read();while(T--)solve();
	n = read();pw[0] = pws[0] = 1;rp(i, n)pws[i] = pws[i - 1], ad(pws[i], pw[i] = 1LL * pw[i - 1] * bas % P);
	scanf("%s%s%s", s[0] + 1, s[1] + 1, s[2] + 1);
	rep(op, 0, 8){
		rp(i, n){
			int x = dx[op] * f(s[0][i]) + dy[op] * f(s[1][i]) + dz[op] * f(s[2][i]);
			x %= 3;
			hs[op] = (1LL * hs[op] * bas + x) % P;
		}
	}
	m = read();
	scanf("%s", s[0] + 1);
	build(1, 1, n);
	out();
	while(m--){
		char op[2];
		int x = read(), y = read();
		scanf("%s", op);
		change(1, x, y, f(*op));
		out();
	}
	return 0;
}

以上是关于题解[JOI Open 2021] Crossing的主要内容,如果未能解决你的问题,请参考以下文章

「题解」:[loj2763][JOI2013]现代豪宅

「JOI Open 2016」摩天大楼(笛卡尔树dp+优化)

The 22nd Japanese Olympiad in Informatics (JOI 2022/2023) Final Round 题解

#3468. 「JOI 2021 Final」有趣的家庭菜园 4(双指针&差分)

Deltix Round, Spring 2021 (open for everyone, rated, Div. 1 + Div. 2) A~D题解

JOI 2020 Final 火灾