1. 程式人生 > >Hihocoder #1602 : 本質不同的回文子串的數量 manacher + BKDRhash

Hihocoder #1602 : 本質不同的回文子串的數量 manacher + BKDRhash

bit clas using font 字符 clu long sin 內存

#1602 : 本質不同的回文子串的數量

時間限制:10000ms 單點時限:1000ms 內存限制:256MB

描述

給定一個字符串S,請統計S的所有子串中,有多少個本質不同的回文字符串?

註意如果兩個位置不同的子串滿足長度相同且對應字符也都相同,則認為這兩個子串本質上是相同的。

輸入

一個只包含小寫字母的字符串S。

對於30%的數據,S長度不超過100。

對於60%的數據,S長度不超過1000。

對於100%的數據,S長度不超過800000。

輸出

回文子串的數量

樣例輸入
abbab
樣例輸出
5
題解:
  跑manacher的時候 hash標記即可
#include <bits/stdc++.h>
inline 
long long read(){long long x=0,f=1;char ch=getchar();while(ch<0||ch>9){if(ch==-)f=-1;ch=getchar();}while(ch>=0&&ch<=9){x=x*10+ch-0;ch=getchar();}return x*f;} using namespace std; const long long INF = 1e14; const int N = 1e6 + 7; unsigned long long P = 10000019ULL; unsigned
long long sqr[N],has[N]; //BKDRHash,最優的字符串hash算法。hash一開始是等於0的 const int seed = 13131; // 31 131 1313 13131 131313 etc.. const int maxn = 2000000+10; char str[maxn]; unsigned long long sumHash[maxn]; //前綴hash值 const int MOD = 2000007; struct StringHash { int first[MOD+2],num; unsigned long long EdgeNum[maxn]; //
表明第i條邊放的數字(就是sumHash那個數字) int next[maxn],close[maxn]; //close[i]表示與第i條邊所放權值相同的開始的最大位置 //就比如baba,現在枚舉長度是2,開始的時候ba,close[1] = 1;表明"ba"開始最大位置是從1開始 //然後枚舉到下一個ba的時候,close[1]就要變成3了,開始位置從3開始了 void init () { num = 0; memset (first,0,sizeof first); return ; } int insert (unsigned long long val,int id) //id是用來改變close[]的 { int u = val % MOD; for (int i = first[u]; i ; i = next[i]) //存在邊不代表出現過,出現過要用val判斷,val才是唯一的,邊還是壓縮後(%MOD)的呢 { if (val == EdgeNum[i]) //出現過了 { int t = close[i]; close[i] = id;//更新最大位置 return t; } } ++num; //沒出現過的話,就加入圖吧 EdgeNum[num] = val; // 這個才是精確的 close[num] = id; next[num] = first[u]; first[u] = num; return 0;//沒出現過 } }H; char a[N]; int ans = 0; map<unsigned long long, int> mp; void gao(int i,int j) { unsigned long long now = has[j] - has[i-1] * sqr[j-i+1]; if(!H.insert(now,1)) ++ans,mp[now]++; } int r[N]; int main() { scanf("%s",a+1); int n = strlen(a+1); sqr[0] = 1;for(int i = 1; i <= n; ++i) sqr[i] = sqr[i-1] * P; for(int i = 1; i <= n; ++i) has[i] = has[i-1] * P + a[i]; int x = 0, p = 0; for(int i = 1; i <= n; ++i) { int j = 0; gao(i,i); if(p > i) j = min(r[2*x-i],p-i); while(i + j + 1 <= n&& a[i+j+1] == a[i-j-1]) { gao(i-j-1,i+j+1); j++; } r[i] = j; if(i+j > p) { p = i + j; x = i; } } H.init(); x = 0,p = 0; for(int i = 2; i <= n; ++i) { int j = 0; if(p > i) j = min(r[2*x-i],p-i+1); while(i+j<=n && a[i+j] == a[i-j-1]) { gao(i-j-1,i+j); ++j; } r[i] = j; if(i+j-1 > p) { p = i+j-1; x = i; } } printf("%d\n",ans); return 0; }

Hihocoder #1602 : 本質不同的回文子串的數量 manacher + BKDRhash