題意:給定乙個字串,求字串本質不同的回文子串個數。
思路:主要參考該篇解題報告
先按照manacher的構造方法改造一遍串,然後跑一遍manacher。求出以i為中心的最長回文串長度p[i]。
然後跑一遍字尾陣列,若已經求得字尾sa[i-1]對答案的貢獻,然後現在計算字尾sa[i],本來是要加上以sa[i]為中心的回文串的個數p[sa[i]]。
我們可以維護乙個tmp,也就是上圖中藍色的框。tmp表示以字元sa[i-1]為中心已經被統計過的回文串的個數。到了當前的sa[i],tmp=min(tmp,h[i]);
每次如果p[x]<=tmp,就continue;否則,ans+=(p[x]-tmp)/2;(/2是因為有#)
#define _crt_secure_no_deprecate#include#include
#include
#include
#include
#include
#include
#include
#include
#include
using
namespace
std;
typedef
long
long
intll;
const
int maxn = 100000*3 + 10
;int
wa[maxn],wb[maxn],wv[maxn],ws[maxn];
int cmp(int *r,int a,int b,int
l)void da(int *r,int *sa,int n,int m)
return;}
int rank[maxn],height[maxn]; //
height[0]:sa[1]?sa[0]?lcp
void calheight(int *r,int *sa,int n)
int rmq[maxn],mm[maxn],best[20
][maxn];
void initrmq(int
n)
return;}
int askrmq(int a,int
b)int lcp(int a,int
b)
return(height[askrmq(a+1
,b)]);
}char
str[maxn],dstr[maxn];
intlenstr,lendstr,p[maxn],r[maxn],sa[maxn];
void init(char *s)
lendstr=lenstr*2+2; dstr[lendstr]='*'
;}void
manacher()
else
while(dstr[i-p[i]]==dstr[i+p[i]])
if(p[i]+i>mx)
}}void
solve()
ans+=(p[sa[i]]-tmp)/2
; tmp=p[sa[i]];
}printf(
"%d\n
",ans);
}int
main()
r[i]=(int
)dstr[i];
}da(r, sa, lendstr+1,256
); calheight(r, sa, lendstr);
//printf("len=%d\n",lendstr);
printf("
case #%d:
",case++); solve();
}//#ifdef local_time
//cout << "[finished in " << clock() - start << " ms]" << endl;
//#endif
return0;
}
不同回文子串數目 hdu 3948
將原串反向後接在後面,中間用乙個沒出現過的字元隔開 如 abab k strlen str 連線後變為 abab9baba0 根據height 排序後 i height i 子串 0 0 0 1 0 9baba0 2 0 a0 3 1 ab9baba0 4 2 aba0 5 3 abab9baba0...
hdu 3948 求不同回文串的個數
求乙個串中不相同的子串可以用字尾陣列求,這題只不過是要求子串是回文串所以也可以用字尾陣列求。求不相同的子串的的演算法中,對於相鄰的兩個字尾 i j 字尾 j 能產生的子串的個數為len height j len為 j 字尾的長度,height i 為字尾 i,j 的最長公共字首。所以求不同子串的個數...
字尾陣列 HDU 4436
做法 首先應用求不同子串的演算法,自然想到字尾陣列,然後就是要統計以非 0 開始的字尾。考慮字尾 akak 1ak 2.an tmp 0 ak 0 tmp i tmp i 1 10 ai 0 sum i sum i 1 tmp i 那麼 以 am開始的字首和就是 sum n sum m 1 tmp ...