zoukankan      html  css  js  c++  java
  • 牛客14894 最长回文

    题面

    题目链接

    https://ac.nowcoder.com/acm/problem/14894

    题目大意

    有两个长度均为n的字符串A和B。

    可以从A中选一个可以为空的子串A[l1..r1],B中选一个可以为空的子串B[l2..r2]

    需要满足r1 = l2,然后把它们拼起来(A[l1..r1]+B[l2..r2])

    求用这样的方法能得到的最长回文串 S 的长度。

    解题思路

    首先对 A , B 串都跑一边 Manacher,分别得到 PA , PB 和处理过的 A , B

    然后再枚举处理过的 A / B,以每个字符作为 S 的中心点,半径为 max(PA , PB) 进行拓展即可

    因为以 i 为中心 PA / PB 为半径的回文串中,它的最小回文长度就达到了 PA / PB - 1

    所以只要从 PA / PB 两端拓展看还能找到多少可以相匹配的字符就可以了

    而假设 S 的中心点为 i , A 提供的是 i - 1 , i - 2 ... ,B 提供的是 i + 1 , i + 2 ...,他们之间相差了 2

    所以当枚举到 A 的第 i 个字符时,需要操作的是 PA[ i ] 和 PB[ i - 2 ]

     

    而拓展的方法有两种,一种是逐一匹配,俗称 brute force

    另一种是 二分拓展的长度 + hash check  来匹配

    第一种做法的复杂度我不太会算,感觉会超时但才跑了500ms?

    而第二种做法显然要快上不少,大概是 50ms

    这里提供两种做法

    AC_Coder_(暴力)

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 3e5 + 10;
    string a , b;
    int pa[N] , pb[N] , res = 1;
    string Manacher(string a , int *p)
    {
        string t = "$#";
        for(auto i : a) t += i , t += '#';
        int mx = 0 , id = 0 ;
        int len = t.size() , ans = 0; 
        for(int i = 1 ; i < len ; i ++)
        {
            p[i] = mx > i ? min(p[2 * id - i] , mx - i) : 1;
            while(t[i + p[i]] == t[i - p[i]]) p[i] ++ ;
            if(mx < i + p[i]) mx = i + p[i] , id = i;
            ans = max(ans , p[i] - 1);
        }
        res = max(res , ans);
        return t;
    }
    signed main()
    {
        int n ;
        cin >> n >> a >> b;
        a = Manacher(a , pa) , b = Manacher(b , pb);
        n = n * 2 + 2;
        int ans = 1;
        for(int i = 2 ; i <= n ; i ++)
        {
            int len = max(pa[i] , pb[i - 2]);
            while(a[i - len] == b[i - 2 + len]) len ++; 
            ans = max(ans , len - 1); 
        }
        cout << ans << '
    ';
        return 0;
    }

    AC_Coder_(hash + 二分)

    #include<bits/stdc++.h>
    #define int long long
    #define ull unsigned long long
    using namespace std;
    const int N = 3e5 + 10;
    const int MOD = 999998639; 
    const int P = 13331;
    string a , b;
    int pa[N] , pb[N] , res = 1;
    ull pre[N] , suf[N] , power[N];
    string Manacher(string a , int *p)
    {
        string t = "$#";
        for(auto i : a) t += i , t += '#';
        int mx = 0 , id = 0 ;
        int len = t.size() , ans = 0; 
        for(int i = 1 ; i < len ; i ++)
        {
            p[i] = mx > i ? min(p[2 * id - i] , mx - i) : 1;
            while(t[i + p[i]] == t[i - p[i]]) p[i] ++ ;
            if(mx < i + p[i]) mx = i + p[i] , id = i;
            ans = max(ans , p[i] - 1);
        }
        res = max(res , ans);
        return t;
    }
    ull get_hash1(int l , int r)
    {
        if(l > r) return -999;
        return (pre[r] - pre[l - 1] * power[r - l + 1] % MOD + MOD) % MOD;
    }
    ull get_hash2(int l , int r)
    {
        if(l > r) return -888;
        return (suf[l] - suf[r + 1] * power[r - l + 1] % MOD + MOD) % MOD;
    }
    void init(int n)
    {
        power[0] = 1;
        for(int i = 1 ; i < N - 5 ; i ++) power[i] = power[i - 1] * P % MOD;
        pre[0] = a[0] ;
        for(int i = 1 ; i < n ; i ++) pre[i] = (pre[i - 1] * P + a[i]) % MOD ;
        suf[n - 1] = b[n - 1];
        for(int i = n - 2 ; i >= 0 ; i --) suf[i] = (suf[i + 1] * P + b[i]) % MOD; 
    }
    signed main()
    {
        int n ;
        cin >> n >> a >> b;
        a = Manacher(a , pa) , b = Manacher(b , pb);
        n = n * 2 + 2;
        init(n);
        int ans = 1;
        for(int i = 2 ; i <= n ; i ++)
        {
            int add = 0;
            int len = max(pa[i] , pb[i - 2]);
            int sa = i - len + 1  , sb = i - 2 + len - 1;
            int l = 0 , r = min(sa - 1 , n - sb);
            while(l <= r)
            {
                int mid = l + r >> 1;
                int l1 = max(0LL , sa - mid) , r1 = min(n , sa - 1);
                int l2 = max(sb + 1 , 0LL) , r2 = min(n , sb + mid);
                if(get_hash1(l1 , r1) == get_hash2(l2 , r2)) 
                l = mid + 1 , add = mid;
                else r = mid - 1; 
            }
            ans = max(ans , add + len - 1);
        }
        cout << ans << '
    ';
        return 0;
    }
    凡所不能将我击倒的,都将使我更加强大
  • 相关阅读:
    C#分部类和分部方法的使用
    C# 关于线程锁lock的使用方法
    Halcon标定流程及注意事项
    C#如何将ListView中的数据导出到Excel中
    Application.DoEvents()的作用
    (C#)使用队列(Queue)解决简单的并发问题
    C#的委托 VS C++的指针
    转载——卷积神经网络(CNN)基础入门介绍
    Linux启动详细过程(开机启动顺序)
    Nginx https 证书配置
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/12809847.html
Copyright © 2011-2022 走看看