[CTSC2014] 企鵝 QQ
題目背景
PenguinQQ 是中國最大、最具影響力的 SNS(Social Networking Services)網站,以實名制為基礎,為使用者提供日誌、群、即時通訊、相簿、集市等豐富強大的網際網路功能體驗,滿足使用者對社交、資訊、娛樂、交易等多方面的需求。
題目描述
小 Q 是 PenguinQQ 網站的管理員,他最近在進行一項有趣的研究——哪些賬戶是同一個人註冊的。經過長時間的分析,小Q發現同一個人註冊的賬戶名稱總是很相似的,例如 Penguin1,Penguin2,Penguin3……於是小 Q 決定先對這種相似的情形進行統計。
小 Q 定義,若兩個賬戶名稱是相似的,當且僅當這兩個字串等長且恰好只有一位不同。例如“Penguin1”和“Penguin2”是相似的,但“Penguin1”和“2Penguin”不是相似的。而小 Q 想知道,在給定的 \(n\) 個賬戶名稱中,有多少對是相似的。
為了簡化你的工作,小Q給你的N 個字串長度均等於L ,且只包含大小寫字母、數字、下劃線以及‘@’共64種字元,而且不存在兩個相同的賬戶名稱。
輸入格式
第一行包含三個正整數 \(N,L,S\)。其中 \(N\) 表示賬戶名稱數量,\(L\) 表示賬戶名稱長度,\(S\) 用來表示字符集規模大小,它的值只可能為 \(2\) 或 \(64\)。
若 \(S\) 等於 \(2\),賬戶名稱中只包含字元 0
和 1
共 \(2\) 種字元;
若 \(S\) 等於 \(64\),賬戶名稱中可能包含大小寫字母、數字、下劃線以及 @
共 \(64\) 種字元。
隨後 \(N\) 行,每行一個長度為 \(L\) 的字串,用來描述一個賬戶名稱。資料保證 \(N\) 個字串是兩兩不同的。
輸出格式
僅一行一個正整數,表示共有多少對相似的賬戶名稱。
樣例 #1
樣例輸入 #1
4 3 64
Fax
fax
max
mac
樣例輸出 #1
4
提示
\(4\) 對相似的字串分別為:Fax 與 fax,Fax 與 max,fax 與 max,max 與 mac。
測試點編號 | \(N\) | \(L\) | \(S\) |
---|---|---|---|
\(1\) | \(50\) | \(10\) | \(64\) |
\(2\) | \(500\) | \(100\) | \(64\) |
\(3\) | \(3000\) | \(100\) | \(2\) |
\(4\) | \(3000\) | \(100\) | \(64\) |
\(5\) | \(30000\) | \(50\) | \(2\) |
\(6\) | \(30000\) | \(50\) | \(64\) |
\(7\) | \(30000\) | \(200\) | \(2\) |
\(8\) | \(30000\) | \(200\) | \(64\) |
\(9\) | \(30000\) | \(200\) | \(2\) |
\(10\) | \(30000\) | \(200\) | \(64\) |
分析
注意到符合題意的字串去掉不同的一位後所形成的字串是相同的。
對於每個字串,計算其去掉某一位後所形成的字串的雜湊值。
這樣會產生至多\(N*L\)個雜湊值,排序後可輸出答案。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+100,INF=0x7fffffff;
typedef unsigned long long ull;
ull key=137,bas[N];
char s[30010];
int n,len,siz,cnt;
ull all[6000100],h[30010];
void init()
{
scanf("%d%d%d",&n,&len,&siz);bas[0]=1;
for(int i=1;i<=len;++i)
bas[i]=bas[i-1]*key;
ull pre,bak;
for(int i=1;i<=n;++i)
{
scanf("%s",s+1);
for(int j=1;j<=len;++j)
{
h[j]=0;
h[j]=h[j-1]*key+s[j];
}
for(int j=1;j<=len;++j)
{
//1~j-1
pre=h[j-1];
//j+1~len
bak=(h[len]-h[j]*bas[len-j])*bas[j];
all[++cnt]=pre+bak;
}
}
sort(all+1,all+1+cnt);
int st=1,ans=0;
for(int i=2;i<=cnt;++i)
{
if(all[i-1]==all[i])++st;
else {ans+=st*(st-1)/2;st=1;}
}
ans+=st*(st-1)/2;cout<<ans;
}
int main()
{
init();
return 0;
}