zoukankan      html  css  js  c++  java
  • Codeforces 1326D1

    题目大意

    T组数据,每组给定一个字符串 s

    求一个最长的字符串 t ,满足:

    1. t 是一个回文串

    2. t = a+b ,a是字符串s的前缀,b是字符串s的后缀,'+' 为拼接两字符串,ab可能为空串


    数据范围

    数据组数不超过 1000

    字符串的总共长度不超过 5000


    解题思路

    可直接使用Hard版本算法

    或本题直接进行下文暴力法


    因为a和b分别是字符串s的前缀和后缀

    因为对于任意的字符串T,设R(T)为T的倒置

    T+回文串+R(T) 仍然是一个回文串

    所以可以直接双指针在s里找出最长的 T和R(T)

    while(L<R&&s[L]==s[R])
        L++,R--;
    

    如果最长的 T 和 R(T) 相拼接恰好等于字符串s(或者中间多一个字符)

    那么说明整个 s 就是个回文串,直接输出


    否则,考虑中间的子串

    根据题意,需要在中间部分寻找最长的回文串

    且这个回文串要满足要么与 T 相邻,要么与 R(T) 相邻

    因为数据范围很小,所以可以直接暴力


    假设中间的子串在s中的位置下标为 [L,R]

    左右两侧寻找两次

    以左侧为例,寻找的方式如下

    • 对于长度为单数的回文串,枚举中间字符的下标 i ,往左右两边 j=i+1,k=i-1 双指针检查
    • 对于长度为双数的回文串,枚举中间位置左侧字符的下标 i ,往左右两边 j=i+1,k=i 双指针检查

    对于范围,需要注意的是

    如果[L,R]内字符个数为奇数,说明以第(L+R)/2个字符为中心的回文串不需要查找(否则整个中间子串就是个回文串),同样以其右侧为中心的回文串也不需要查找

    如果[L,R]内字符个数为偶数,只需要查找以第(L+R)/2个字符为中心的回文串即可,不需要查找以(L+R)/2右侧为中心的回文串

    int LeftMaxLen=1;
    for(i=L;i<=(L+R)/2;i++)
    {
    	if(i==(L+R)/2&&(R-L+1)%2!=0)//i在中心且为奇数直接退出
    		break;
    	for(j=i+1,k=i-1;k>=L&&j<=R;j++,k--)
    		if(s[j]!=s[k])
    			break;
    	if(k<L||j>R)
    		if(LeftMaxLen<(i-L)*2+1)
    			LeftMaxLen=(i-L)*2+1;
    	
    	if(i==(L+R)/2)//只要i在中心就退出
    		break;
    	for(j=i+1,k=i;k>=L&&j<=R;j++,k--)
    		if(s[j]!=s[k])
    			break;
    	if(k<L||j>R)
    		if(LeftMaxLen<(i-L+1)*2)
    			LeftMaxLen=(i-L+1)*2;
    }
    

    LeftMaxLen变量储存左侧回文串的最大长度

    因为单个字符也算回文串,故初始值为 1


    右边的处理也一样

    但是范围处理稍有不同

    因为(L+R)/2为向下取整

    如果[L,R]内字符个数为奇数,说明以第(L+R)/2个字符为中心的回文串和以其左侧为中心的回文串都不需要查找

    如果[L,R]内字符个数为偶数,根据向下取整,只需要判断以第(L+R)/2+1个字符为中心的回文串即可,不需要判断以其左侧为中心的回文串

    所以循环条件直接写成i>(L+R)/2

    int RightMaxLen=1;
        for(i=R;i>(L+R)/2;i--)
        {
            for(j=i+1,k=i-1;j<=R&&k>=L;j++,k--)
                if(s[j]!=s[k])
                    break;
            if(j>R||k<L)
                if(RightMaxLen<(R-i)*2+1)
                    RightMaxLen=(R-i)*2+1;
    			
    		if(i==(L+R)/2+1&&(R-L+1)%2==0)//个数为偶数且i在中心右侧位置,退出
    			break;
            for(j=i,k=i-1;j<=R&&k>=L;j++,k--)
                if(s[j]!=s[k])
                    break;
            if(j>R||k<L)
                if(RightMaxLen<(R-i+1)*2)
                    RightMaxLen=(R-i+1)*2;
        }
    

    最后,输出左边+中间+右边即可





    完整程序

    (31ms / 2000ms)

    #include<bits/stdc++.h>
    using namespace std;
    string s;
    void solve()
    {
        cin>>s;
        int i,j,k,L=0,R=s.size()-1;
        while(L<R&&s[L]==s[R])
            L++,R--;
        if(L>=R)
        {
            cout<<s<<'
    ';
            return;
        }
        int LeftMaxLen=1;
        for(i=L;i<=(L+R)/2;i++)
        {
    		if(i==(L+R)/2&&(R-L+1)%2!=0)
    			break;
            for(j=i+1,k=i-1;k>=L&&j<=R;j++,k--)
                if(s[j]!=s[k])
                    break;
            if(k<L||j>R)
                if(LeftMaxLen<(i-L)*2+1)
                    LeftMaxLen=(i-L)*2+1;
    		
    		if(i==(L+R)/2)
    			break;
            for(j=i+1,k=i;k>=L&&j<=R;j++,k--)
                if(s[j]!=s[k])
                    break;
            if(k<L||j>R)
                if(LeftMaxLen<(i-L+1)*2)
                    LeftMaxLen=(i-L+1)*2;
        }
        
        int RightMaxLen=1;
        for(i=R;i>(L+R)/2;i--)
        {
            for(j=i+1,k=i-1;j<=R&&k>=L;j++,k--)
                if(s[j]!=s[k])
                    break;
            if(j>R||k<L)
                if(RightMaxLen<(R-i)*2+1)
                    RightMaxLen=(R-i)*2+1;
    			
    		if(i==(L+R)/2+1&&(R-L+1)%2==0)
    			break;
            for(j=i,k=i-1;j<=R&&k>=L;j++,k--)
                if(s[j]!=s[k])
                    break;
            if(j>R||k<L)
                if(RightMaxLen<(R-i+1)*2)
                    RightMaxLen=(R-i+1)*2;
        }
        
        for(i=0;i<L;i++)
            cout<<s[i];
        if(LeftMaxLen>=RightMaxLen)
            for(i=L,j=0;j<LeftMaxLen;i++,j++)
                cout<<s[i];
        else
            for(i=R-RightMaxLen+1;i<=R;i++)
                cout<<s[i];
        for(i=R+1;i<s.size();i++)
            cout<<s[i];
        cout<<'
    ';
    }
    int main()
    {
        ios::sync_with_stdio(0);
        cin.tie(0);cout.tie(0);
        int T;cin>>T;
        while(T--)
            solve();
        
        return 0;
    }
    
  • 相关阅读:
    【POJ 3162】 Walking Race (树形DP-求树上最长路径问题,+单调队列)
    【POJ 2152】 Fire (树形DP)
    【POJ 1741】 Tree (树的点分治)
    【POJ 2486】 Apple Tree (树形DP)
    【HDU 3810】 Magina (01背包,优先队列优化,并查集)
    【SGU 390】Tickets (数位DP)
    【SPOJ 2319】 BIGSEQ
    【SPOJ 1182】 SORTBIT
    【HDU 5456】 Matches Puzzle Game (数位DP)
    【HDU 3652】 B-number (数位DP)
  • 原文地址:https://www.cnblogs.com/stelayuri/p/12529118.html
Copyright © 2011-2022 走看看