洛谷P4503 [CTSC2014]企鵝QQ
阿新 • • 發佈:2018-12-14
某種神奇的HASH
這個hash貌似是叫RK-Hash,和普通的hash不一樣的是他可以O(1)的計算字串的hash值,操作上也有很大區別
操作?
普通的hash是一次計算,最後只保留了一個字串的hash值,但是這種hash是將每個串的每一個字首的hash存起來,也就是說存到一個二維數組裡,hsh[i][k]表示第i個串到第k位時的hash值,看起來沒有什麼用,但是看下面這個神奇操作:給定兩個串yinshenzuijule,yinshentaiqiangle,我需要你幫我判斷他們的前k位是不是相等,是不是發現有點用處了?讓你判斷後k位呢?不知所措了?我們發現hsh[i][k]—>hsh[i][len]的區別在於後一個是前一個不斷乘以進位制然後加上第k+j位的過程,也就是說後一個串的hash值減去前面一個串不斷乘進位制但是不加上第k+j位的hash,最後得到的就是最後len-k位的hash值,可以自己手玩一下,然後我們可以根據這個操作,將它推廣到任意字串,對於l~r,我們可以用hsh[i][r]-hsh[i][l-1]*base^(r-l+1),就能愉快的得到這個串的hash值了
對於本題?
我們對於每個串,對它從前到後做一遍這個操作,再從後向前做一次這個操作,然後我們列舉刪掉哪一位,然後將這位之前的部分和之後的部分合並一下,然後判等就好了,貌似要用點加法原理?
程式碼
//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define ull unsigned long long
const int M=300500;
const int bs1=149,bs2=137;
const int bs3=233,bs4=213;
int n,m,l,ans;
char s[M];
ull tp[M],hs1[M][205],hs2[M][205];
void mhash(int x,char g[])
{
for (int i=1;i<=l;i++)
hs1[x][i]=hs1[x][i-1]*bs1+g[i];
for(int i=l;i>=1;i--)
hs2[x][i]=hs2[x][i+1]*bs2+g[i];
return ;
}
int main( )
{
scanf("%d%d%d",&n,&l,&m);
for (int i=1;i<=n;i++)
{
scanf("%s",s+1);
mhash(i,s);
}
for (int i=1;i<=l;i++)
{
for (int k=1;k<=n;k++)
tp[k]=hs1[k][i-1]*bs3+hs2[k][i+1]*bs4;
sort(tp+1,tp+1+n);
int sam=1;
for (int k=2;k<=n;k++)
{
if(tp[k]==tp[k-1])ans+=sam++;
else sam=1;
}
}
printf("%d",ans);
return 0;
}