P14187 [ICPC 2024 Hangzhou R] AUS

题目传送门

欢迎光顾我的博客喵

首先考虑一些比较简单的情况:

(下面设 \(n1\)\(s1\) 字符串长,\(n2\)\(s2\) 字符串长,\(n3\)\(s3\) 字符串长。若三个字符串长度相同,我们设 \(n\) 为三个串共同的字符串长)

(另外,若字符串 \(a,b\) 满足 \(a=b\) ,那么我们称 \(a\)\(b\) 匹配)

(再额外规定一下,若字符 \(c1,c2\) 满足 \(F(c1)=F(c2)\) ,我们称 \(c1\) 约等于 \(c2\)

如果 \(n1!=n2\) ,那么显然 \(s1,s2\) 是无法匹配上的,直接输出 \(NO\)

如果 \(n1=n2\)\(n1!=n3\) ,那么显然有解,因为此时 \(s1\) 无论怎么变换,由于长度不同, \(s3\) 都不会和 \(s1\) 匹配,输出 \(YES\)

接下来就是 \(n1=n2=n3\) 的情况了。

首先我们从左往右扫一下 \(s1,s2\) ,显然 \(\forall i \in [1,n],i \in Z,F(s1_{i})=F(s2_{i})\) 。那这两个字符就跟一个字符没区别了对吧。约等于是把俩字符合并了。

我们经过一番思索后,考虑用并查集维护 约等于一个字符 的 所有字符 组成的连通块,当我们扫到 \(s1_{i}\)\(s2_{i}\) 时,我们就直接用并查集的 \(merge\) 操作给俩字符进行一个合并。

然后我们再扫一遍 \(s1\)\(s3\) 。如果 \(\forall i \in [1,n],i \in Z,F(s1_{i})=F(s3_{i})\) ,那么 \(s3\) 的每个字符都约等于 \(s1\) ,那这两串也就没什么区别了,输出 \(NO\) 。否则输出 \(YES\)

至于初始化,和普通并查集一样, \(fa_{i}=i\) 即可。

我当时考试的时候其实想过一个问题,就是如果 \(s3\) 的某个字符虽然不约等于它对应位置 \(s1\) 的字符,但是如果没有映射的位置了,导致它不得不映射到 \(s1\) 对应位置的那个字符的映射位上怎么办?

其实并不会出现这种情况,因为除掉该位置的字符,剩下的 25 个字母最多映射到 25 个位置(因为会出现多个字符的 \(F\) 值相等,也就是映射到同一位置的情况,所以实际还会小),它总是有映射的位置的。

代码:

P14187
#include<bits/stdc++.h>
#define int long long
using namespace std;

inline int read(){
	int x=0,f=1;char c=getchar();
	while(c<48){
		if(c=='-') f=-1;
		c=getchar();
	}
	while(c>47) x=(x<<1)+(x<<3)+(c^48),c=getchar();
	return x*f;
}

inline void write(int x){
	if(x<0) putchar('-'),x=-x;
	if(x<10) putchar(x+'0');
	else write(x/10),putchar(x%10+'0');
}

const int N=1314;
int T,n1,n2,n3,n;
char s1[N],s2[N],s3[N],fa[32];

inline int FIND(int x){
	return (x==fa[x]?x:fa[x]=FIND(fa[x]));
}

inline void merge(int x,int y){
	int fx=FIND(x),fy=FIND(y);
	if(fx==fy) return ;
	fa[fy]=fx;
}

signed main(){
	T=read();
	while(T--){
		scanf("%s%s%s",s1+1,s2+1,s3+1);
		n1=strlen(s1+1),n2=strlen(s2+1),n3=strlen(s3+1);
		for(int i=1;i<=26;i++){
			//初始化:把每个字符当做并查集的一个点,初始令fa[i]=i 
			fa[i]=i;
		}
		if(n1!=n2){//特殊情况1 
			printf("NO\n");
			continue;
		}
		else if(n1!=n3){//特殊情况2 
			printf("YES\n");
			continue;
		}
		n=n1;
		for(int i=1;i<=n;i++){//将s1,s2的字符合并 
			merge(s1[i]-'a'+1,s2[i]-'a'+1);
		}
		int fl=0;
		for(int i=1;i<=n;i++){
			int x=s1[i]-'a'+1,y=s3[i]-'a'+1;
			int fx=FIND(x),fy=FIND(y);
			if(fx!=fy){
				//只要有一个不约等于就说明可行
				fl=1;break;
			}
		}
		if(fl){
			printf("YES\n");
		}
		else{
			//否则就全部约等于 
			printf("NO\n");
		}
	}
	return 0;
}
posted @ 2025-10-13 21:09  qwqSW  阅读(5)  评论(0)    收藏  举报