1. 程式人生 > >洛谷P4503 [CTSC2014]企鵝QQ

洛谷P4503 [CTSC2014]企鵝QQ

某種神奇的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; }