zoukankan      html  css  js  c++  java
  • Prefix-Suffix Palindrome

    D1,

    题意:

    输入T组数据;

    每组数据一行字符串str;

    现在让你选str的前缀和后缀,使得前缀+后缀是回文串,且使它的长度是最长的。

    注意:前缀或后缀的字符串 可以为空。

    ///样例解释
    /*
    5
    a
    abcdfdcecba
    abbaxyzyx
    codeforces
    acbba
    */
    /*
    a
    abcdfdcba  abcdfd是给定字符串的前缀,cba是字符串的后缀
    xyzyx   此前缀为空,xyzyx是字符串的后缀
    c
    abba  a是给定字符串的前缀+bba是给定字符串的后缀
    */
    

     做法:

    我们先考虑给定字符串的前缀和后缀相匹配的长度。

    比如像给定了字符串“abcdefecba”

    我们可以发现他的前缀和后缀相匹配的长度为3,即“abc” 与“cba”是想匹配的。(这里的相匹配的意思就是找到最长的前缀 + 相同长度的后缀为回文串;)

    那我们考虑剩下的字符串“defe” 在主串中的下标为:4567;

    因为答案为前缀+后缀的形式;

    所以,我们需要考虑(4,4)和(4,5)和(4,6)和(4,7)和(5,7)和(6,7)和(7,7)

    这些区间是否可以构成回文串,并记录下最长的那个回文串;

    #include"stdio.h"
    #include"string.h"
    #include"stack"
    #include"map"
    #include"math.h"
    #include"vector"
    #include"queue"
    #include"algorithm"
    using namespace std;
    #define OK printf("
    ");
    #define Debug printf("this_ok
    ");
    typedef long long ll;
    #define scanll(a,b) scanf("%lld%lld",&a,&b);
    #define scanl(a) scanf("%lld",&a);
    #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
    ",a);
    #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
    ",a);
    const ll mod=998244353;
    typedef pair<int,int> PII;
    inline int read(){
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
        return s * w;
    }
    
    const int N = 201010;
    const int dirx[4] = {0,1,0,-1};
    const int diry[4] = {-1,0,1,0};
    int n,k,len;
    int a[N];
    char str[N];
    vector<int>Q1,Q2;
    int check(int l,int r){ ///判断字符串的(l,r)区间是否为回文串,若是返回1,否则,返回0;
        while(l < r){
            if(str[l] != str[r]) return 0;
            l ++; r --;
        }
        return 1;
    }
    int main()
    {
         int T = read();
         while(T --){
             scanf("%s",str + 1);
             int loc = 0;len = strlen(str + 1);
             int l = 1,r = len;
             while(l <= r){ ///此函数可以找到前缀和后缀的最长长度。
                if(str[l] != str[r]) break;
                l ++; r --;
             }
    
             if(l > r) {  ///如果l>r了,那其本身就是回文串,直接输出即可
                printf("%s
    ",str + 1); continue;
             }
    
             l --; r ++; ///注意,str[l] != str[r]; 所以l--,r++;
             int L1 = l + 1,R1 = r - 1; ///L1为剩下字符串的最左下标,R1为剩下字符串的最右下标
            // printf("L1 = %d R1 = %d
    ",L1,R1);
             int mid1 = 0,mid2 = 0;
             for(int i = L1; i <= R1; i ++){ ///暴力枚举最左下标所构成的区间,判断是否为回文串,并将值保存在mid1中;
                 if(check(L1,i) == 0) continue;
                 mid1 = i;
             }
             for(int i = R1; i >= L1; i --){ ///暴力枚举最右下标所构成的区间,判断是否为回文串,并将值保存在mid2中
                if(check(i,R1) == 0) continue;
                mid2 = i;
             }
            // printf("mid1 = %d mid2= %d
    ",mid1,mid2);
             int len1 = mid1 - L1 + 1; ///计算以最左下标构成的区间最长为多少
             int len2 = R1 - mid2 + 1;///计算最右下标构成的区间长度最长为多少
             if(len1 >= len2) { ///比较长度,输入较长那一部分;
                for(int i = 1; i <= l; i ++) printf("%c",str[i]);
                for(int i = L1; i <= mid1; i ++) printf("%c",str[i]);
                for(int i = r; i <= len; i ++) printf("%c",str[i]);
                OK continue;
             } else  {
                 for(int i = 1; i <= l; i ++) printf("%c",str[i]);
                for(int i = mid2; i <= R1; i ++) printf("%c",str[i]);
                for(int i = r; i <= len; i ++) printf("%c",str[i]);OK continue;
             }
         }
    }
    
    /*
    5
    2
    1 4 5 5
    5 2 1 5 5 3
    */
    

    D2,数据范围比D1大;(字符串hash)

    从而我们不能去枚举区间;

    所以我们需要考虑的是,如何在O(n)的时间复杂度中,找到最长的回文串;

    基本思路和上面一样;

    不同之处:我们在处理为匹配的字符串的时候,我们可以先把他的字符串hash值算出来;即上面所讲样例:字符串“defe”,我们把其hash值算出来;

    然后枚举长度,判断这个长度是否为回文串;

    #include"stdio.h"
    #include"string.h"
    #include"stack"
    #include"map"
    #include"math.h"
    #include"vector"
    #include"queue"
    #include"algorithm"
    using namespace std;
    #define OK printf("
    ");
    #define Debug printf("this_ok
    ");
    typedef long long ll;
    typedef unsigned long long ull;
    #define scanll(a,b) scanf("%lld%lld",&a,&b);
    #define scanl(a) scanf("%lld",&a);
    #define printl(a,b) if(b == 0) printf("%lld ",a); else printf("%lld
    ",a);
    #define print_int(a,b) if(b == 0) printf("%d ",a); else printf("%d
    ",a);
    const ull mod1=19260811;
    const ull mod2=999998639;
    ull base = 2333;
    typedef pair<int,int> PII;
    inline int read(){
        int s = 0, w = 1; char ch = getchar();
        while(ch < '0' || ch > '9')   { if(ch == '-') w = -1; ch = getchar(); }
        while(ch >= '0' && ch <= '9') { s = (s << 3) + (s << 1) + (ch ^ 48); ch = getchar(); }
        return s * w;
    }
    ///调式的时候一直把ull的格式符弄成了%u,导致调式就一直莫名奇妙错失%ull
    const int N = 2010100;
    const int dirx[4] = {0,1,0,-1};
    const int diry[4] = {-1,0,1,0};
    int n,k,len;
    int a[N];
    char str[N];
    ull a1[N],c1[N];
    ull b1[N];
    
    int mark = 1;int Len;
    int check(int l,int r){ ///判断区间[l,r]是否为回文串,与D1不同,这里是使用字符串的hash进行判断,并且要注意长度为奇数和偶数时的区别;
        int len = r - l + 1; int mid;
        ull A1,B1;
        if(len % 2 == 1){
            mid = l + (len / 2);
             A1 = (a1[mid - 1] - a1[l - 1] * c1[mid - l] % mod2 + mod2) % mod2;
             B1 = (b1[mid + 1] - b1[r + 1] * c1[r - mid] % mod2 + mod2) % mod2;
            if(A1 == B1) return 1;
        } else  {
             mid = l + (len / 2) - 1;
             A1 = (a1[mid] - a1[l - 1] * c1[mid - l + 1] % mod2 + mod2) % mod2;
             B1 = (b1[mid + 1] - b1[r + 1] * c1[r - mid] % mod2 + mod2) % mod2;
            if(A1 == B1) return 1;
        }
        return 0;
    }
    int main()
    {
         int T = read();
         while(T --){
             scanf("%s",str + 1);
             int loc = 0;len = strlen(str + 1);
             int l = 1,r = len;
             while(l <= r){
                if(str[l] != str[r]) break;
                l ++; r --;
             }
             if(l > r) {
                printf("%s
    ",str + 1); continue;
             }
             l --; r ++;
             
             int L1 = l + 1,R1 = r - 1;
             c1[0] = 1; Len = R1 - L1 + 1;
             a1[Len] = a1[Len + 1] = 0;
             b1[Len] = b1[Len + 1] = 0;
             for(int i = L1; i <= R1; i ++){ ///这里把区间[L1,R1]的hash值算出来(从左到右),注意,我下标是从1开始的;
                 a1[i - L1 + 1] = (a1[i - L1] * base + (str[i] - 'a' + 1)) % mod2;;
                 c1[i - L1 + 1] = c1[i - L1] * base % mod2;;
             }
             for(int i =  R1; i >= L1; i --){///把区间[L1,R1]的反向hash值算出来(从右到左);
                b1[i - L1 + 1] = (b1[i - L1 + 2] * base + (str[i] - 'a' + 1)) % mod2;
             }
             
             int mid1 = 0,mid2 = Len;
             for(int i = 1; i <= Len; i ++){ ///枚举长度
                if(check(1,i) == 0) continue;
                mid1 = i;
             }
             for(int i = Len; i >= 1; i --){ ///枚举长度
                if(check(i,Len) == 0) continue;
                mid2 = i;
             }
             int len1 = mid1; int len2 = Len - mid2 + 1;
             if(len1 >= len2) {
                for(int i = 1; i <= l; i ++) printf("%c",str[i]);
                for(int i = L1; i <= mid1 + l; i ++) printf("%c",str[i]);
                for(int i = r; i <= len; i ++) printf("%c",str[i]);
                OK continue;
             } else  {
                 for(int i = 1; i <= l; i ++) printf("%c",str[i]);
                for(int i = R1 - len2 + 1; i <= R1; i ++) printf("%c",str[i]);
                for(int i = r; i <= len; i ++) printf("%c",str[i]);OK continue;
             }
         }
    }
    
    /*
    5
    2
    1 4 5 5
    5 2 1 5 5 3
    */
    
  • 相关阅读:
    函数的逻辑读成零
    SQL逻辑读变成零
    体系结构中共享池研究
    执行计划基础 动态采样
    执行计划基础 统计信息
    识别低效率的SQL语句
    oracle 知识
    XPATH 带命名空间数据的读取
    ACTIVITI 研究代码 之 模版模式
    ACTIVITI 源码研究之命令模式执行
  • 原文地址:https://www.cnblogs.com/yrz001030/p/12533094.html
Copyright © 2011-2022 走看看