codeforces MemSQL start[c]up Round 2 - online version B 最长公共子系列

题目链接:  http://codeforces.com/contest/335/problem/B

分析: 第一眼看上去串的长度为5*10^4, 冒似只能用O(n)的算法可解. 而这样的算法从来没见过......

      其实不然, 注意一个条件"如果有存在长度为100的回文子串则输出长度为100的,否则输出最长的",

      可以发现: 一个长度大于100的回文串都可以变成长度为100的

      如: 长度为101的只要删除中间的一个就变为长度为100的,

          长度为102的删除中间两个也变为长度为100的......

      意思就是, 得到的结果串的长度一定小于等于100.

      又因为原串中全为小写字母, 所以最多出现26个字母,

     还可以发现, 当长度达到2600时, 肯定会出现长度为100回文子串, 因为肯定会有一个字母出现次数大于等于100

      也就是说, 最终, 我们最后取2600个字母, 那么可以用O(n^2)(这里n<=2600) 算法...........

代码:

 

#include<iostream>

#include<cstdio>

#include<string>

using namespace std;

const int maxn=2601;

int dp[maxn][maxn]; ///dp[i][j]表示区间[i,j]中回文子串的长度

int L[maxn][maxn];

int R[maxn][maxn];

int main(){

    

    string s; cin>>s;

    int len=min(maxn,(int)s.size());

    for(int i=0;i<len;++i)  

        dp[i][i]=1;

    for(int i=1; i<len; ++i)

        for(int j=0; j+i<len; ++j) {

            int k=j+i;

            if(dp[j+1][k]>dp[j][k]) {

                dp[j][k]=dp[j+1][k];

                L[j][k]=j+1;

                R[j][k]=k;

            }

            if(dp[j][k-1]>dp[j][k]) {

                dp[j][k]=dp[j][k-1];

                L[j][k]=j;

                R[j][k]=k-1;

            }

            if(s[j]==s[k]&&dp[j+1][k-1]+2>dp[j][k]) {

                dp[j][k]=dp[j+1][k-1]+2;

                L[j][k]=j+1;

                R[j][k]=k-1;

            }

        }

    int ans=min(dp[0][len-1],100);

    char ch[102]="";

    int ls=0, rs=len-1;

    int lc=0, rc=ans-1;

    while(lc<=rc){ 

        if(lc==rc){

            ch[lc]=s[ls]; break;

        }

        if(s[ls]==s[rs]){

            ch[lc]=ch[rc]=s[ls];

            lc++; rc--; 

            ls++; rs--; 

            continue;

        }

        int lx=ls, rx=rs;

        ls=L[lx][rx];

        rs=R[lx][rx];

    }

    cout<<ch<<endl;

    return 0;

}






 

 

你可能感兴趣的:(codeforces)