题意:
给出n个字符串,如果两个字符串中含有相同的字母说明两个字符串相同,问有多少个不同的字符串。
思路:
具有传递性,如果a , b相同,b , c相同,那么a , c也一定相同
考虑用并查集维护。
但是n < = 2 e 5所以枚举两个字符串显然不现实。
一共只有26个字母,维护在某个字符串里每个字母的出现次数,如果u , v两个字母在这个字符串里都出现过,合并u , v所在集合,这样就能实现传递性了。
代码:
// Problem: D. Secret Passwords // Contest: Codeforces - Codeforces Round #603 (Div. 2) // URL: https://codeforces.com/problemset/problem/1263/D // Memory Limit: 256 MB // Time Limit: 1000 ms // // Powered by CP Editor (https://cpeditor.org) #include<iostream> #include<cstdio> #include<string> #include<ctime> #include<cmath> #include<cstring> #include<algorithm> #include<stack> #include<queue> #include<map> #include<set> #include<sstream> using namespace std; typedef long long ll; const int maxn=2e5+100; int root[30],vis[30],siz[30]; int Find(int x){ if(x!=root[x]) root[x]=Find(root[x]); return root[x]; } int main() { for(int i=0;i<=27;i++) root[i]=i; int n;cin>>n; for(int i=1;i<=n;i++){ string s;cin>>s; memset(siz,0,sizeof siz); for(int j=0;s[j];j++){ int now=s[j]-'a'+1; siz[now]++;vis[now]=1; } for(int j=1;j<=26;j++){ if(!siz[j]) continue; for(int k=1;k<=26;k++){ if(!siz[k]) continue; int fu=Find(j),fv=Find(k); if(fu!=fv) root[fu]=fv; } } } int ans=0; for(int i=1;i<=26;i++){ // if(i<=4) cout<<i<<" "<<Find(i)<<" "<<ans<<endl; if(vis[i]&&i==Find(i)) ans++; } cout<<ans<<endl; return 0; }