Codeforces Global Round 7 D

D1. Prefix-Suffix Palindrome (Easy version)

easy版本 我们只需要n2 dp预处理出快速判断回文串
然后我们再通过双指针O(n)求解最大串

int dp[5010][5010];
void solve(){
    string s;cin>>s;
    int n=s.size();s=')'+s;
    for(int i=0;i<=n;i++)for(int j=0;j<=n;j++)dp[i][j]=0;
    for(int i=1;i<=n;i++){
        dp[i][i]=1;
        if(i!=1&&s[i]==s[i-1])dp[i-1][i]=1;
    }
    for(int len=3;len<=n;len++){
        for(int i=1,j=i+len-1;j<=n;j++,i++){
            if(s[i]==s[j])dp[i][j]|=dp[i+1][j-1];
        }
    }
    int ans=0;string S;
    for(int i=1;i<=n;i++)if(dp[1][i]){
        if(ans<i)S=s.substr(1,i),ans=i;
    }
    for(int i=1;i<=n;i++)if(dp[i][n]){
        if(ans<n-i+1)S=s.substr(i,n-i+1),ans=n-i+1;
    }
    int l=0;
    for(int i=1,j=n;i<j;i++,j--){
        if(s[i]!=s[j])break;
        else{
            int t=0;
            for(int k=i+1;k<j;k++)if(dp[i+1][k])t=max(t,k-i);
            for(int k=j-1;k>i;k--)if(dp[k][j-1])t=max(t,j-k);
            if(ans<i*2+t){
                ans=i*2+t;
                l=i;
            }
        }
    }
    if(!l)cout<<S<<endl;
    else{
        S.clear();
        string r=s.substr(1,l);
        S+=r;
        int i=l,j=n-l+1,t=0;
        string q;
        for(int k=i+1;k<j;k++)if(dp[i+1][k]){
            if(t<k-i){
                t=k-i;
                q=s.substr(i+1,t);
            }
        }
        for(int k=j-1;k>i;k--)if(dp[k][j-1]){
            if(t<j-k){
                t=j-k;
                q=s.substr(k,t);
            }
        }
        S+=q;
        std::reverse(r.begin(), r.end());
        S+=r;
        cout<<S<<endl;
    }
}

D2. Prefix-Suffix Palindrome (Hard version)

相比于上一个 我们还可以发现的性质就是
我们最开始就可以贪到彻底 直接去找最长的前缀后缀
因为我们不可能前面会有一个很小的前缀后缀with一个字符串 如果是的话这样字符串贪到彻底也是相同的ans
所以我们问题就变成了一个字符串中求最长的前缀/后缀回文串
我们直接O(n)的manacher就可以了
manacher是求出每一个p[i]以i坐标为中心的最长回文半径
我们只要p[i]==i 那么就是最长前缀了不是吗
后缀我们reverse一遍即可

inline int work(string s, int n) {
    string ss = "$#";
    vector<int>p;
    for (int i = 0; i < n; i++) ss += s[i], ss += "#";
    p.push_back(1);
    int mx = 0, id = 0, ans = 1;
    for (int i = 1; i < (int)ss.length(); i++) {
        p.push_back(mx > i ? min(p[2*id-i], mx - i) : 1);
        while (i + p[i] < (int)ss.length() && ss[i+p[i]] == ss[i-p[i]]) ++p[i];
        if (i == p[i]) ans = max(ans, p[i]);
        if (i + p[i] > mx) mx = i + p[i], id = i;
    }
    return ans - 1;
}
void solve(){
    string s;cin>>s;int n=s.size();s=')'+s;
    int l=0,r=n+1;
    for(int i=1,j=n;i<j;i++,j--) {
        if (s[i] != s[j])break;
        l = i, r = j;
    }
    string t;
    for(int i=l+1;i<r;i++)t.push_back(s[i]);
    int ans_l=work(t,r-l-1);
    reverse(all(t));
    int ans_r=work(t,r-l-1);
    if(ans_l>ans_r)reverse(all(t)),swap(ans_l,ans_r);
    for(int i=1;i<=l;i++)cout<<s[i];
    for(int i=0;i<ans_r;i++)cout<<t[i];
    for(int i=l;i>=1;i--)cout<<s[i];
    cout<<endl;
}
posted @ 2022-11-02 17:30  ycllz  阅读(23)  评论(0)    收藏  举报