一つの未知のハッカーは、次のコンテストの問題を取得するには、システムのテストAtForcesの管理者のパスワードを取得したいです。それを達成するために、彼は管理者のオフィスに潜入し、n個のパスワードのリストを一枚の紙を盗んだ - 文字列、小さなラテン文字で構成されています。
ハッカーは家に行き、AtForcesをハックする準備を始めました。彼は、システムがパスワードだけ盗まれたリストから、システムはaとbは次のようにパスワードの等価性を決定することを含んでいることがわかりました。
AとBの両方に存在する文字がある場合、2つのパスワードおよびBは同等です。
AとBの両方に相当し、リストからパスワードcが存在する場合に2つのパスワードとBは同等です。
パスワードがシステムに設定されていると等価一方がシステムにアクセスするために適用されている場合、ユーザがシステムにアクセスされます。
例えば、リストは、パスワードその後、「」、「B」、「AB」、「D」、パスワード「」、「B」、「AB」が互いに同等であるが、パスワード「d」があるが含まれている場合リストから他のパスワードと同じではありません。換言すれば、:
管理者のパスワードは「B」である場合、あなたは、このパスワードのいずれかの使用してシステムにアクセスすることができます:「」、「b」を、「AB」。
管理者のパスワードは、あなただけの「d」を使用してシステムにアクセスすることができ、「D」です。
リストからわずか1つのパスワードは、テスト・システムから管理者のパスワードです。ヘルプハッカーがシステムへの保証のアクセスに必要なパスワードの最小数を計算します。ハッカーがシステムに設定されたパスワードを知っていないことに注意してください。
入力
リスト内のパスワードの数-最初の行は、整数N(1≤n≤2⋅105)を含みます。非空の文字列SI、最大50文字の長さと-次のn行は、リストからパスワードが含まれています。パスワードの一部が同じであってもよいです。
すべてのパスワードの長さの合計が106文字を超えていないことが保証されています。それらのすべては小文字のみラテン文字で構成されています。
出力
シングルラインでは、パスワードの最小数は、システムにアクセスすることを保証することができますそれらの使用を印刷します。
例として
、入力
4 、B 、ABのDの出力2 入力3 AB 、BC 、ABCの出力1 入力1 codeforces 出力1 注システムにアクセスするためにパスワードのいずれかを使用する第2の例示的ハッカーを必要とします。
質問の意味:
与えられたn個の文字列。
列A、同じ条件B:
aとbは、現在の文字に等しく、
aとbがB列に等しい
異なる文字列の数を求めて
アイデア:
同じ文字の存在が同じであるので、それは必要な文字数とは本質的に無関係です。
文字列の場合、文字間の通信ブロックとなり、すべての文字は、最後のいくつかの独立した十分を参照する必要があります。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 200005;
vector<int>ans;
string a[maxn];
int fa[maxn],vis[maxn],vis2[maxn];
int findset(int x)
{
if(fa[x] == x)return x;
return fa[x] = findset(fa[x]);
}
bool Union(int x,int y)
{
int rx = findset(x),ry = findset(y);
if(rx != ry)
{
fa[rx] = ry;
return true;
}
return false;
}
int main()
{
int n;scanf("%d",&n);
for(int i = 1;i <= 200;i++)fa[i] = i;
for(int i = 1;i <= n;i++)
{
cin >> a[i];
}
for(int i = 1;i <= n;i++)
{
int len = (int)a[i].size();
int flag = 1;
for(int j = 0;j < len;j++)
{
for(int k = j;k < len;k++)
{
int t1 = a[i][j] - 'a' + 1;
int t2 = a[i][k] - 'a' + 1;
Union(t1,t2);
if(!vis[t1])
{
ans.push_back(t1);
vis[t1] = 1;
}
if(!vis[t2])
{
ans.push_back(t2);
vis[t2] = 1;
}
}
}
}
int res = 0, len = (int)ans.size();
for(int i = 0;i < len;i++)
{
int x = findset(ans[i]);
if(!vis2[x])
{
res++;
vis2[x] = 1;
}
}
printf("%d\n",res);
return 0;
}