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;
}