洛谷 p4503【企鹅QQ】[CTSC2014] 企鹅 QQ - 洛谷
这道题主要运用了前缀和后缀的思想。
因为没有相同的字符串,所以要找出相似的字符串,就是去掉一个位置,这个位置前后分别哈希,前后哈希相加和如果相等,那么这两个字符串必然是相似的。
#include<cstring>
#include<algorithm>
using namespace std;
typedef unsigned long long ull;
const int maxn=30010;
/*
一开始打max会一直报错,所以没用这个。
这个要与常用单词区分开,以免概念模糊。
*/
ull hs1[30010][233], hs2[30010][233], hs[30010];
char ch[30010][233];
int n, l, s;
inline void line(int x) {//inline 在这里用处不大,可不打
for (int i = 1; i <= l; i++) {
hs1[x][i] = hs1[x][i - 1] * 131 + ch[x][i];//计算前缀
}
for (int i = l; i >= 1; i--) {
hs2[x][i] = hs2[x][i + 1] * 233 + ch[x][i];//计算后缀
}
}
int main(){
scanf("%d%d%d", &n, &l, &s);
for (int i = 1; i <= n; i++) {
scanf("%s", ch[i] + 1); //细节加1
line(i);
}
int ans = 1, Ans = 0;
for (int i = 1; i <= l; i++) {
for (int j = 1; j <= n; j++) {
hs[j] = hs1[j][i - 1] * 237 + hs2[j][i + 1]*211;//计算去掉i点之外的从1到n的哈希值
//237,211可以替换任意较大质数(如果某几个数据过不了),这里乘也是多一层保险
}
sort(hs + 1, hs + 1 + n);
//把哈希值相同的排在一起
for (int j = 1; j< n; j++) { //此处注意小于,别打等于,虽然问题不大
if (hs[j] == hs[j + 1]) Ans += ans, ans++;
//如果有k个点哈希值都相同,那么把这k个点看做节点,多一个点就会多出k个相似,然后节点数加1
else ans = 1;
//如果不同,节点置1;
}
}
printf("%d\n", Ans);
return 0;
}