Palindrome HDU - 6230
阿新 • • 發佈:2018-12-02
題目中要求的串,可以概括為兩個迴文串的組合:_____ i ____ j _____
以 i 和以 j 為中心的兩個迴文串拼接起來,注意 i 的迴文串範圍要覆蓋 j,j 的迴文串範圍要覆蓋 i
設p[i]是以 i 為中心的迴文串覆蓋半徑(不包括 i )
那麼要符合三個條件:j>i ; j<=i+p[i] ; i>=j-p[j] ;
先用Manacher演算法算出以每個點為中心的最長迴文串長度
再按照 i 從1~n維護滿足( j-p[j]>=i )的 j 在樹狀數組裡,然後查詢[ i+1,i+p[i] ]範圍內的 j 有多少個,加起來就是答案
水平太菜,比賽的時候只想到了馬拉車,沒想到怎麼去優化。樹狀陣列板子記一下吧。
看到題解都是用樹狀陣列寫的,我就試著用線段樹寫了一下,一直re,我覺得是線段樹爆了,開不了那麼的結構體陣列,用指標寫應該可以吧,太麻煩了,我就不試了。只能瞭解一下樹狀陣列了。
#include<iostream> #include<string> #include<cstring> #include<cmath> #include<iomanip> #include<stdio.h> #include<algorithm> #include<map> #include<vector> #include<queue> #include<stack> using namespace std; # define inf 0x3f3f3f3f # define maxn 500000+10 # define ll long long ll c[maxn]; int n; inline int lowbit(int x) { return x & -x; } void update(int idx, int v) { while (idx <= n) { c[idx] += v; idx += lowbit(idx); } } ll query(int x) // The sum of 1 to x { ll ans = 0; while(x > 0) { ans += c[x]; x -= lowbit(x); } return ans; } struct code { int l,r; ll sum; } tree[maxn*6]; void buid(int t,int l,int r) { tree[t].l=l; tree[t].r=r; tree[t].sum=0; if(l==r) return ; int mid=(l+r)/2; buid(2*t,l,mid); buid(2*t+1,mid+1,r); } void add(int t,int posi) { tree[t].sum++; if(tree[t].l==tree[t].r) return ; int mid =(tree[t].l+tree[t].r)/2; if(posi<=mid) add(2*t,posi); else add(2*t+1,posi); } ll queuy(int t,int l,int r) { if(tree[t].l==l&&tree[t].r==r) return tree[t].sum; ll ans=0,mid=(tree[t].l+tree[t].r)/2; if(r<=mid) ans=queuy(2*t,l,r); else if(l>mid) ans=queuy(2*t+1,l,r); else ans=queuy(2*t,l,mid)+queuy(2*t+1,mid+1,r); return ans; } char s[2*maxn],A[2*maxn]; int B[2*maxn]; int ans[2*maxn]; vector<int>dap[maxn]; void manacher(char s[],int len) { int l=0; A[l++]='$'; A[l++]='#'; for(int i=0; i<len; i++) { A[l++]=s[i]; A[l++]='#'; } A[l]=0; int mx=0; int id=0; for(int i=0; i<l; i++) { B[i]=mx>i?min(B[2*id-i],mx-i):1; while(A[i+B[i]]==A[i-B[i]]) { B[i]++; } if(i+B[i]>mx) { mx=i+B[i]; id=i; } } } int main() { int T; scanf("%d",&T); while(T--) { int num=0; scanf("%s",s); int len=strlen(s); n=len; manacher(s,len); for(int i=0; i<2*len+2; i++) { if(A[i]>='a'&&A[i]<='z') { ans[++num]=B[i]/2-1; } } // buid(1,0,len-1); memset(c,0,sizeof(c)); for(int i=1; i<=len; i++) dap[i].clear(); for(int i=1; i<=len; i++) dap[i-ans[i]].push_back(i); ll t=0; for(int i=1; i<=len; i++) { int lax=dap[i].size(); for(int j=0; j<lax; j++) update(dap[i][j],1); t+=query(i+ans[i])-query(i); } printf("%lld\n",t); } return 0; }