【SPOJ1297】Palindrome (SA+RMQ)

求最长回文串。把原串翻转后,加在原串后面,中间插入一个辨别字符。然后求SA,Height。然后枚举每个字母作为回文串中心,分长度为奇数和偶数去讨论:奇数求 suffix(i)和suffix(n-i+1)的最长公共前缀,偶数则求suffix(i)和suffix(n-i+2)(当然,i=1时不成立) 。然后问题就是求最长公共前缀了,转换为RMQ问题,O(nlogn)预处理,O(1)询问即可.

  1 const maxn=2419;
  2
  3 var
  4  x,y,rank,sa,h,c:array[0..maxn] of longint;
  5  s:ansistring;
  6  f:array[0..maxn,0..15] of longint;
  7  t,q,n:longint;
  8
  9 function max(x,y:longint):longint; begin if x>y then exit(x) else exit(y); end;
 10 function min(x,y:longint):longint; begin if x<y then exit(x) else exit(y); end;
 11 procedure swap(var x,y:longint);var tmp:longint; begin tmp:=x; x:=y;y:=tmp; end;
 12 procedure make;
 13 var i,j,p,tot:longint;
 14 begin
 15  p:=1;
 16  while p<n do
 17   begin
 18    fillchar(c,sizeof(c),0);
 19    for i:= 1 to n-p do y[i]:=rank[i+p];
 20    for i:= n-p+1 to n do y[i]:=0;
 21    for i:= 1 to n do inc(c[y[i]]);
 22    for i:= 1 to n do inc(c[i],c[i-1]);
 23    for i:= 1 to n do
 24     begin
 25      sa[c[y[i]]]:=i;
 26      dec(c[y[i]]);
 27     end;
 28    fillchar(c,sizeof(c),0);
 29    for i:= 1 to n do x[i]:=rank[i];
 30    for i:= 1 to n do inc(c[x[i]]);
 31    for i:= 1 to n do inc(c[i],c[i-1]);
 32    for i:= n downto 1 do
 33     begin
 34      y[sa[i]]:=c[x[sa[i]]];
 35      dec(c[x[sa[i]]]);
 36     end;
 37    for i:= 1 to n do sa[y[i]]:=i;
 38    tot:=1;
 39    rank[sa[1]]:=1;
 40    for i:= 2 to n do
 41     begin
 42      if (x[sa[i]]<>x[sa[i-1]]) or (x[sa[i]+p]<>x[sa[i-1]+p]) then inc(tot);
 43      rank[sa[i]]:=tot;
 44     end;
 45    p:=p<<1;
 46   end;
 47 end;
 48
 49 procedure makeh;
 50 var i,j,p:longint;
 51 begin
 52  h[1]:=0; p:=0;
 53  for i:= 1 to n do
 54   begin
 55    p:=max(p-1,0);
 56    if rank[i]=1 then continue;
 57    j:=sa[rank[i]-1];
 58    while (i+p<=n) and (j+p<=n) and (s[i+p]=s[j+p]) do inc(p);
 59    h[rank[i]]:=p;
 60   end;
 61 // for i:= 1 to n do write(h[i],‘ ‘);
 62 // writeln;
 63 end;
 64
 65 procedure rmq;
 66 var i,j:longint;
 67 begin
 68  fillchar(f,sizeof(f),$7f);
 69  for i:= 1 to n do f[i,0]:=h[i];
 70  for i:= 1 to trunc(ln(n)/ln(2)) do
 71   for j:= 1 to n-1<<i+1 do
 72    f[j,i]:=min(f[j,i-1],f[j+1<<(i-1),i-1]);
 73 end;
 74
 75 function lcp(x,y:longint):longint;
 76 var t:longint;
 77 begin
 78  x:=rank[x]; y:=rank[y];
 79  if x>y then swap(x,y);
 80  if x<y then x:=x+1;
 81  t:=trunc(ln(y-x+1)/ln(2));
 82  exit(min(f[x,t],f[y-1<<t+1,t]));
 83 end;
 84
 85 procedure init;
 86 var i,j,tot:longint;
 87  ch:char;
 88 begin
 89  readln(s);
 90  s:=s+‘#‘;
 91  for i:= length(s)-1 downto 1 do s:=s+s[i];
 92  n:=length(s);
 93  for i:= 1 to n do x[i]:=ord(s[i]);
 94  fillchar(c,sizeof(c),0);
 95  for i:= 1 to n do inc(c[x[i]]);
 96  for i:= 1 to 180 do inc(c[i],c[i-1]);
 97  for i:= 1 to n do
 98   begin
 99    sa[c[x[i]]]:=i;
100    dec(c[x[i]]);
101   end;
102  rank[sa[1]]:=1;
103  tot:=1;
104  for i:= 2 to n do
105   begin
106    if x[sa[i]]<>x[sa[i-1]] then inc(tot);
107    rank[sa[i]]:=tot;
108   end;
109  make;
110  makeh;
111  rmq;
112 end;
113
114 procedure solve;
115 var ans,st,i,k:longint;
116 begin
117  ans:=0;st:=0;
118  for i:= 1 to n do
119   begin
120    k:=lcp(i,n-i+1);
121    if k*2-1>ans then
122     begin
123      st:=i-k+1;
124      ans:=k*2-1;
125     end;
126    if i>1 then
127     begin
128      k:=lcp(i,n-i+2);
129      if k*2>ans then
130       begin
131        st:=i-k;
132        ans:=k*2;
133       end;
134     end;
135   end;
136  for i:= st to st+ans-1 do write(s[i]);
137 end;
138
139 Begin
140  init;
141  solve;
142 End.

时间: 2025-01-11 02:55:40

【SPOJ1297】Palindrome (SA+RMQ)的相关文章

【BZOJ3489】A simple rmq problem kd-tree

[BZOJ3489]A simple rmq problem Description 因为是OJ上的题,就简单点好了.给出一个长度为n的序列,给出M个询问:在[l,r]之间找到一个在这个区间里只出现过一次的数,并且要求找的这个数尽可能大.如果找不到这样的数,则直接输出0.我会采取一些措施强制在线. Input 第一行为两个整数N,M.M是询问数,N是序列的长度(N<=100000,M<=200000) 第二行为N个整数,描述这个序列{ai},其中所有1<=ai<=N 再下面M行,每

【CF932G】Palindrome Partition 回文自动机

[CF932G]Palindrome Partition 题意:给你一个字符串s,问你有多少种方式,可以将s分割成k个子串,设k个子串是$x_1x_2...x_k$,满足$x_1=x_k,x_2=x_{k-1}...x_i=x{k-i+1}$. $|s|\le 10^6$ 题解:设字符串的长度为n,考虑字符串$T=s_1s_ns_2s_{n-1}...$.问题就转化成了:求将原串划分成若干个长度为偶数的回文子串的方案数. 首先我们有一种暴力的想法,设f[i]表示将前i个字符分成若干个回文子串的方

【LeetCode】Palindrome Partitioning II 解题报告

[题目] Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s. For example, given s = "aab", Return 1 since the palindrome partitioning ["aa&

【LeetCode】Palindrome Partitioning 解题报告

[题目] Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. For example, given s = "aab", Return [ ["aa","b"], ["a","a",

【BZOJ】【3489】A simple rmq problem

KD-Tree(乱搞) Orz zyf教给蒟蒻做法 蒟蒻并不会这题正解……(可持久化树套树?...Orz 对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足$ ( pre[i]<ql \ and \ nex[i]>qr\ and\ i \in [ql,qr] ) $ 然后我们以(i,pre[i],nex[i])为坐标……将所有点抽象到三维空间中,每次查询就相当于是一次区域求最值! 这题我的感受: 因为前面做了两道区域求和的……然后思路

【leetcode】Palindrome Number (easy)

Determine whether an integer is a palindrome. Do this without extra space. Some hints: Could negative integers be palindromes? (ie, -1) If you are thinking of converting the integer to string, note the restriction of using extra space. You could also

LeetCode【9】. Palindrome Number --java的实现

Palindrome Number Determine whether an integer is a palindrome. Do this without extra space. Some hints: Could negative integers be palindromes? (ie, -1) If you are thinking of converting the integer to string, note the restriction of using extra spa

【leetcode】Palindrome Partitioning

Palindrome Partitioning Given a string s, partition s such that every substring of the partition is a palindrome. Return all possible palindrome partitioning of s. For example, given s = "aab",Return [ ["aa","b"], ["a&qu

【LeetCode】Palindrome Partitioning II

Palindrome Partitioning II  Given a string s, partition s such that every substring of the partition is a palindrome. Return the minimum cuts needed for a palindrome partitioning of s. For example, given s = "aab",Return 1 since the palindrome p