zoukankan      html  css  js  c++  java
  • URAL 1297 求最长回文字符串

    有种简单的方法,数组从左到右扫一遍,每次以当前的点为中心,只要左右相等就往左右走,这算出来的回文字符串是奇数长度的

    还有偶数长度的回文字符串就是以当前扫到的点和它左边的点作为中心,然后往左右扫

    这是O(n^2)的复杂度,这道题过还是没有问题的

    这里我主要练习的是另外的利用后缀数组加RMQ算法来解决这个问题

    大致思想跟上面一致

    首先将字符串反转贴在原字符串末尾,将字符通过ASCII码转化为字符,之间用一个1分开,最后贴一个0

    然后得到它的后缀数组以及height[]数组

    那么找回文字符也是扫一遍,每次以当前点作为偶数情况和奇数情况的中心

    然后找到后来倒置的字符串对应字符的位置,这样二者的前缀一个是往前走的,一个是往后走的,正好贴一块就是回文的

    但是这个查询为加快速度,就要用RMQ算法,求得区间内height数组的最小值

      1 #include <cstdio>
      2 #include <cstring>
      3 #include <iostream>
      4 #include <cmath>
      5 using namespace std;
      6 #define MAXN 2010
      7 int sa[MAXN] , height[MAXN] , _rank[MAXN];
      8 int wa[MAXN] , wb[MAXN] , wsf[MAXN] , wv[MAXN] , r[MAXN];
      9 int dp[MAXN][15];
     10 char str[MAXN];
     11 
     12 int cmp(int *r , int a , int b , int l)
     13 {
     14     return r[a]==r[b] && r[a+l]==r[b+l];
     15 }
     16 
     17 void getSa(int *r , int *sa , int n , int m)
     18 {
     19     int i,j,p;
     20     int *x=wa , *y=wb , *t;
     21 
     22     for(i=0 ; i<m ; i++) wsf[i]=0;
     23     for(i=0 ; i<n ; i++) wsf[x[i]=r[i]]++;
     24     for(i=1 ; i<m ; i++) wsf[i]+=wsf[i-1];
     25     for(i=n-1 ; i>=0 ; i--) sa[--wsf[x[i]]]=i;
     26 
     27     p=1;
     28     for(j=1 ; p<n ; j*=2 , m=p)
     29     {
     30         for(p=0 , i=n-j ; i<n ; i++) y[p++]=i;
     31         for(i=0 ; i<n ; i++) if(sa[i]>=j) y[p++]=sa[i]-j;
     32 
     33         for(i=0 ; i<n ; i++) wv[i]=x[y[i]];
     34         for(i=0 ; i<m ; i++) wsf[i]=0;
     35         for(i=0 ; i<n ; i++) wsf[wv[i]]++;
     36         for(i=1 ; i<m ;  i++) wsf[i]+=wsf[i-1];
     37         for(i=n-1 ; i>=0 ; i--)sa[--wsf[wv[i]]]=y[i];
     38 
     39         t=x , x=y , y=t;
     40         x[sa[0]]=0;
     41         for(i=1,p=1;i<n;i++)
     42             x[sa[i]] = cmp(y , sa[i-1] , sa[i] , j)?p-1:p++;
     43     }
     44     return ;
     45 }
     46 
     47 void callHeight(int *r , int *sa , int n)
     48 {
     49     int i,j,k=0;
     50     for(i=1 ; i<=n ; i++) _rank[sa[i]]=i;
     51   //  for(i=0 ; i<n ; i++) cout<<"_rank: "<<_rank[i]<<endl;
     52     for(i=0 ; i<n ; height[_rank[i++]]=k)
     53         for(k?k--:0 , j=sa[_rank[i]-1]; r[i+k]==r[j+k] ; k++);
     54     return ;
     55 }
     56 
     57 
     58 void ST(int n)
     59 {
     60     //将height数组进行RMQ询问
     61     memset(dp , 0x3f , sizeof(dp));
     62     for(int i=1 ; i<=n ; i++) dp[i][0]=height[i];
     63     for(int j=1 ; (1<<(j-1))<n+1 ; j++)
     64         for(int i=1 ; i<=n ; i++)
     65             dp[i][j] = min(dp[i][j-1] , dp[i+(1<<(j-1))][j-1]);
     66 
     67     return;
     68 }
     69 
     70 int get_min(int s , int t)
     71 {
     72     int len = t-s+1;
     73     int l=floor(log(len*1.0)/log(2.0));
     74     return min(dp[s][l] , dp[t-(1<<l)+1][l]);
     75 }
     76 
     77 void solve(int n , int &left , int &right)
     78 {
     79     int ans = 0;
     80     //奇数情况
     81     for(int i=0 ; i<n ; i++){
     82         int j=2*n-i;
     83         int s=min(_rank[i] , _rank[j]);
     84         int t=max(_rank[i] , _rank[j]);
     85         int tmp = get_min(s+1 , t);
     86         if(ans<tmp*2-1){
     87             ans = tmp*2-1;
     88             left=i-tmp+1 , right=i+tmp-1;
     89         }
     90     }
     91     //偶数情况
     92     for(int i=0 ; i<n ; i++){
     93         int j = 2*n-i+1;
     94         int s=min(_rank[i] , _rank[j]);
     95         int t=max(_rank[i] , _rank[j]);
     96         int tmp = get_min(s+1 , t);
     97         if(ans<tmp*2){
     98             ans = tmp*2;
     99             left=i-tmp , right=i+tmp-1;
    100         }
    101     }
    102     return;
    103 }
    104 
    105 int main()
    106 {
    107   //  freopen("a.in" , "r" , stdin);
    108     while(~scanf("%s" , str))
    109     {
    110         int len = strlen(str);
    111         r[len]=1;
    112         for(int i=0 ; i<len ; i++){
    113             r[i] = (int)str[i];
    114             r[2*len-i] = r[i];
    115         }
    116         r[2*len+1]=0;
    117 
    118         getSa(r , sa , 2*len+2 , 255);
    119         callHeight(r , sa , 2*len+1);
    120         //建立RMQ查询数组
    121         ST(2*len+1);
    122         int left=1 , right=1;
    123         solve(len , left , right);
    124         str[right+1]='';
    125         printf("%s
    " , str+left);
    126     }
    127     return 0;
    128 }
  • 相关阅读:
    转:修改虚拟机参数
    NhiberNate 和linq学习博客园网址
    如何配置sqlserver 以允许远程连接
    Mongodb安装配置文档
    IIS安装和配置
    Mvc篇
    在Castle中使用nhibernate
    多线程
    WCF REST系列文章汇总(共9篇)
    测试Api工具Fiddler
  • 原文地址:https://www.cnblogs.com/CSU3901130321/p/4391291.html
Copyright © 2011-2022 走看看