zoukankan      html  css  js  c++  java
  • UVA

    题目链接:https://vjudge.net/problem/UVA-11475

    题意:

    给出一个字符串,问在该字符串后面至少添加几个字符,使得其成为回文串,并输出该回文串。

    题解:

    实际上是求该字符串的“最长回文后缀”,有多种做法,其中用字符串哈希的方法最方便而且速度最快。

    字符串哈希:

    从字符串的最后一个字符开始,往前进行计算两个哈希值,其中一个按“先高位后低位”的方法计算,另一个按“先低位后高位”的方法计算。如果在某个位置,两个哈希值相等,那么表明该后缀为回文串,求最长的那个即可。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <vector>
     6 #include <cmath>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 using namespace std;
    13 typedef long long LL;
    14 const int INF = 2e9;
    15 const LL LNF = 9e18;
    16 const int MOD = 1e9+7;
    17 const int MAXN = 2e5+100;
    18 
    19 const LL seed = 13331;
    20 char str[MAXN];
    21 int main()
    22 {
    23     while(scanf("%s",str)!=EOF)
    24     {
    25         int len = strlen(str);
    26         int pos = len-1;
    27         LL hash1 = 0, hash2 = 0, s = 1;
    28         for(int i = len-1; i>=0; i--)
    29         {
    30             hash1 *= seed, hash1 += str[i];
    31             hash2 += str[i]*s, s *= seed;
    32             if(hash1==hash2)
    33                 pos = i-1;
    34         }
    35         for(int i = 0; i<len; i++) putchar(str[i]);
    36         for(int i = pos; i>=0; i--) putchar(str[i]);
    37         putchar('
    ');
    38     }
    39 }
    View Code

    KMP:

    1. 根据next数组的next[len]即为字符串前缀与后缀的最长匹配(不包括重叠的情况),可以将字符串的逆串接在其前面,中间用一个分割符隔开,得到新串,求出新串的next数组

    1.1 逆串放在前面是因为用逆串的前缀去匹配原串的后缀。

    1.2 中间加个分隔符是用于防止逆串匹配到逆串那里去,即防止过界。

    2. 假设新串的长度为len, 那么next[len]即为可节省的最大长度,因而只需添加len-next[len]个字符即可。

    代码如下:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 #include <vector>
     6 #include <cmath>
     7 #include <queue>
     8 #include <stack>
     9 #include <map>
    10 #include <string>
    11 #include <set>
    12 using namespace std;
    13 typedef long long LL;
    14 const int INF = 2e9;
    15 const LL LNF = 9e18;
    16 const int MOD = 1e9+7;
    17 const int MAXN = 2e5+100;
    18 
    19 char x[MAXN];
    20 int Next[MAXN];
    21 void get_next(char x[], int m)
    22 {
    23     int i, j;
    24     j = Next[0] = -1;
    25     i = 0;
    26     while(i<m)
    27     {
    28         while(j!=-1 && x[i]!=x[j]) j = Next[j];
    29         Next[++i] = ++j;
    30     }
    31 }
    32 
    33 char str[MAXN];
    34 int main()
    35 {
    36     while(scanf("%s",str)!=EOF)
    37     {
    38         int len = strlen(str);
    39         int m = 2*len+1;
    40         for(int i = 0; i<len; i++)
    41         {
    42             x[len-1-i] = str[i];
    43             x[len+1+i] = str[i];
    44         }
    45         x[len] = '$'; x[m] = 0;
    46         get_next(x, m);
    47 
    48         int pos = len-Next[m]-1;
    49         for(int i = 0; i<len; i++) putchar(str[i]);
    50         for(int i = pos; i>=0; i--) putchar(str[i]);
    51         putchar('
    ');
    52     }
    53 }
    View Code

    后缀数组:

    1.将逆串接在原串的后面,中间用一个分隔符隔开,得到新串。求出新串的后缀数组。

    2.枚举原串在新串中的每一个位置i,该位置代表着新串的一个后缀i,设逆串首字符在原串中的位置为j,同样代表着新串的一个后缀j。加入后缀i与后缀j个最长公共前缀lcp满足:i+lcp==len,即表明最长公共前缀已经延伸到原串的串尾,所以该原串的后缀i为回文串。同样,求出最长的那个即可。

    代码如下:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 #include <vector>
      6 #include <cmath>
      7 #include <queue>
      8 #include <stack>
      9 #include <map>
     10 #include <string>
     11 #include <set>
     12 using namespace std;
     13 typedef long long LL;
     14 const int INF = 2e9;
     15 const LL LNF = 9e18;
     16 const int MOD = 1e9+7;
     17 const int MAXN = 2e5+100;
     18 
     19 bool cmp(int *r, int a, int b, int l)
     20 {
     21     return r[a]==r[b] && r[a+l]==r[b+l];
     22 }
     23 
     24 int r[MAXN], sa[MAXN], Rank[MAXN], height[MAXN];
     25 int t1[MAXN], t2[MAXN], c[MAXN];
     26 void DA(int str[], int sa[], int Rank[], int height[], int n, int m)
     27 {
     28     n++;
     29     int i, j, p, *x = t1, *y = t2;
     30     for(i = 0; i<m; i++) c[i] = 0;
     31     for(i = 0; i<n; i++) c[x[i] = str[i]]++;
     32     for(i = 1; i<m; i++) c[i] += c[i-1];
     33     for(i = n-1; i>=0; i--) sa[--c[x[i]]] = i;
     34     for(j = 1; j<=n; j <<= 1)
     35     {
     36         p = 0;
     37         for(i = n-j; i<n; i++) y[p++] = i;
     38         for(i = 0; i<n; i++) if(sa[i]>=j) y[p++] = sa[i]-j;
     39 
     40         for(i = 0; i<m; i++) c[i] = 0;
     41         for(i = 0; i<n; i++) c[x[y[i]]]++;
     42         for(i = 1; i<m; i++) c[i] += c[i-1];
     43         for(i = n-1; i>=0; i--) sa[--c[x[y[i]]]] = y[i];
     44 
     45         swap(x, y);
     46         p = 1; x[sa[0]] = 0;
     47         for(i = 1; i<n; i++)
     48             x[sa[i]] = cmp(y, sa[i-1], sa[i], j)?p-1:p++;
     49 
     50         if(p>=n) break;
     51         m = p;
     52     }
     53 
     54     int k = 0;
     55     n--;
     56     for(i = 0; i<=n; i++) Rank[sa[i]] = i;
     57     for(i = 0; i<n; i++)
     58     {
     59         if(k) k--;
     60         j = sa[Rank[i]-1];
     61         while(str[i+k]==str[j+k]) k++;
     62         height[Rank[i]] = k;
     63     }
     64 }
     65 
     66 int dp[MAXN][20], mm[MAXN];
     67 void initRMQ(int n, int b[])
     68 {
     69     mm[0] = -1;
     70     for(int i = 1; i<=n; i++)
     71         dp[i][0] = b[i], mm[i] = ((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
     72     for(int j = 1; j<=mm[n]; j++)
     73     for(int i = 1; i+(1<<j)-1<=n; i++)
     74         dp[i][j] = min(dp[i][j-1], dp[i+(1<<(j-1))][j-1]);
     75 }
     76 
     77 int RMQ(int x, int y)
     78 {
     79     if(x>y) swap(x, y);
     80     x++;
     81     int k = mm[y-x+1];
     82     return min(dp[x][k], dp[y-(1<<k)+1][k]);
     83 }
     84 
     85 char str[MAXN];
     86 int main()
     87 {
     88     while(scanf("%s", str)!=EOF)
     89     {
     90         int len = strlen(str);
     91         int n = 2*len+1;
     92         for(int i = 0; i<len; i++)
     93         {
     94             r[i] = str[i];
     95             r[n-1-i] = str[i];
     96         }
     97         r[len] = '$'; r[n] = 0;
     98         DA(r, sa, Rank, height, n, 128);
     99         initRMQ(n, height);
    100 
    101         int pos = len-1;
    102         for(int i = 0; i<len; i++)
    103         {
    104             int lcp = RMQ(Rank[i], Rank[len+1]);
    105             if(i+lcp==len)
    106             {
    107                 pos = i-1;
    108                 break;
    109             }
    110         }
    111         for(int i = 0; i<len; i++) putchar(str[i]);
    112         for(int i = pos; i>=0; i--) putchar(str[i]);
    113         putchar('
    ');
    114     }
    115 }
    View Code
  • 相关阅读:
    java基础(七) java四种访问权限
    java基础(六) switch语句的深入解析
    JavaSe: 不要小看了 Serializable
    对于培训出身的同学,接下来该怎么学习技术?
    Java Tomcat7性能监控与优化详解
    模仿spring-aop的功能,利用注解搭建自己的框架。
    动态页面技术EL
    如何在mysql客户端即mysql提示符下执行操作系统命令
    通过notepad++将混乱的xml配置的格式进行美化
    shell脚本中,for基于列表进行循环的实现方法
  • 原文地址:https://www.cnblogs.com/DOLFAMINGO/p/8478766.html
Copyright © 2011-2022 走看看