• Codeforces 1326D2


    Description

    思路

    先求出最长的回文的前后缀,然后求每个最长回文区间能不能和前缀或后缀接起来,取接起来后长度最大的那个。
    基本就是纯的马拉车算法了。就是要注意边界处理的细节,很容易出问题。我把前后缀的位置处理为开区间,回文区间为闭区间。这样边界相等就可以接起来。详见代码。

    #include <bits/stdc++.h>
    using namespace std;
    const int N = 2e6 + 10;
     
    char ss[N];
    string s;
    string ans;
    int len[N];
     
    void mana() { //马拉车
        s.clear();
        ans.clear();
        s.push_back('$');
        s.push_back('#');
        for(int i = 0; ss[i]; i++) {
            s.push_back(ss[i]);
            s.push_back('#');
        }
     
        int a = 1, p = 1;
        for(int i = 1; i < s.size(); i++) {
            if(i < p && len[2 * a - i] < p - i) len[i] = len[2 * a - i];
            else {
                int l = p - i;
                while(i + l < s.size() && s[i + l] == s[i - l]) l++;
                len[i] = l;
                a = i;
                p = i + l;
            }
        }
        //for(int i = 0; ss[i]; i++) cout << len[(i + 1) * 2] / 2 << " ";
    }
     
    int main() {
        ios::sync_with_stdio(false);
        int t;
        cin >> t;
        while(t--) {
            cin >> ss;
            mana();
            int p1 = 1, p2 = s.size() - 1;
            while(p1 < p2 && s[p1] == s[p2]) p1++, p2--;
            if(p1 >= p2) {cout << ss << endl; continue;}
            int mx = 0, mxp, fx;
            for(int i = 1; i < s.size(); i++) {
                int l = i - len[i] + 1;
                int r = i + len[i] - 1; //l, r为回文区间(闭区间)
                if(l > p1 && r < p2) continue;  //[l, r]与前后缀都接不起来
                if(l - 1 < s.size() - r - 1) {  //[l, r]离前后边界哪个就接到哪个前或后缀
                    if(2 * (i - 1) + 1 > mx) {
                        mxp = i;
                        mx = 2 * (i - 1) + 1;
                        fx = 0;
                    }
                }  else {
                    if((s.size() - i - 1) * 2 + 1 > mx) {
                        mxp = i;
                        mx = (s.size() - i - 1) * 2 + 1;
                        fx = 1;
                    }
                }
            }
            if(fx == 0) { //接到不同前后缀方向不同
                int d = (mx - 1) / 2;
                for(int i = mxp - d; i < mxp; i++) ans.push_back(s[i]);
                for(int i = mxp; i >= mxp - d; i--) ans.push_back(s[i]);
                for(char ch : ans) if(ch != '#') cout << ch;
                cout << endl;
            } else {
                int d = (mx - 1) / 2;
                for(int i = mxp + d; i > mxp; i--) ans.push_back(s[i]);
                for(int i = mxp; i <= mxp + d; i++) ans.push_back(s[i]);
                for(char ch : ans) if(ch != '#') cout << ch;
                cout << endl;
            }
        }
        
        
    }
    
  • 相关阅读:
    Mysql存储引擎
    数据库事务的四大特性以及事务的隔离级别
    万万没想到,面试中,连 ClassLoader类加载器 也能问出这么多问题
    万万没想到,JVM内存区域的面试题也可以问的这么难?
    SQL Server读取及导入Excel数据
    SQL Server加密与解密
    线程之间如何通信
    mybatis 批量更新 批量添加
    vue echarts 从后台获取数据形成饼图,柱状图,折线图
    vue 视频播放
  • 原文地址:https://www.cnblogs.com/limil/p/12626215.html
Copyright © 2020-2023  润新知