P8270 [USACO22OPEN] Subset Equality S

洛谷

发现字母的范围比较小,但是也没有小多少,那么多半是需要对字母组合求解。

第一想法就是给计入的字母状压,确认是否相同。

但是字符串长度又太长了,并且不好优化,只能放弃。

那么该怎么组合?

我们发现影响两个字符串在选择这几个字符后的串是否相等需要看两点:

  1. 字符的数量

  2. 不同字符之间的位置关系

第一个特别水,每个字符都简单判断一下数量即可,重点在第二点。

两个相同字符串中任意选择两个字符组成的串一定相等,这是显然的。

那么如果这个逆命题成立,即任意选择两个字符在原有的两个字符串中组成串相等,则字符串一定相同,这样我们就可以直接判断任意两个字符了。

虽然这个结论看起来很一眼,但是作为题解还是要稍微证明一下的。

问题可以转化为我们已知每两个组成的字符串,是否能够得到唯一的字符串。

那么我们肯定是有第一位的,只要在这个字符对应其它字符组成的串中的第一个字符就是这个字符,那么这个字符就是第一个字符。

如果找不到那么就一定不存在合法匹配。

那么找到第一个,删掉,再找下一个开头,就是第二个了。

以此类推,最后对应的字符串就是唯一的。

那么代码就好写了。

代码:

#include<bits/stdc++.h>
using namespace std;
char s1[100005],s2[100005],c1[100005],c2[100005],q[100005];
bool ans[40][40];
int n;
signed main(){
	cin>>s1+1>>s2+1;
	int len1=strlen(s1+1),len2=strlen(s2+1);
	for(int i='a';i<='r';i++){
		for(int j=i;j<='r';j++){
			int l1=0,l2=0;
			for(int k=1;k<=len1;k++)if(s1[k]==i||s1[k]==j)c1[++l1]=s1[k];
			for(int k=1;k<=len2;k++)if(s2[k]==i||s2[k]==j)c2[++l2]=s2[k];
			ans[i-'a'][j-'a']=1;
			if(l1!=l2)ans[i-'a'][j-'a']=0;
			else for(int k=1;k<=l1;k++)if(c1[k]!=c2[k])ans[i-'a'][j-'a']=0;
		}
	}
	cin>>n;
	while(n--){
		cin>>q+1;
		int len=strlen(q+1);
		bool fl=1;
		for(int i=1;i<=len;i++){
			for(int j=i;j<=len;j++){
				fl&=ans[q[i]-'a'][q[j]-'a'];
			}
		}
		if(fl)cout<<"Y";
		else cout<<"N";
	}
	return 0;
}

posted @ 2025-12-07 13:05  huhangqi  阅读(4)  评论(0)    收藏  举报