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;
    }
    
  • 相关阅读:
    【树链剖分】【线段树】bzoj2157 旅游
    【高斯消元】【异或方程组】poj1222 EXTENDED LIGHTS OUT
    【树链剖分】【线段树】bzoj3626 [LNOI2014]LCA
    【dfs】bzoj3563 DZY Loves Chinese
    【高斯消元】【异或方程组】【bitset】bzoj1923 [Sdoi2010]外星千足虫
    【高斯消元】bzoj1013 [JSOI2008]球形空间产生器sphere
    【博弈论】bzoj1115 [POI2009]石子游戏Kam
    【最近公共祖先】【树链剖分】CODEVS 1036 商务旅行
    【块状树】【博弈论】bzoj3729 Gty的游戏
    【博弈论】【SG函数】bzoj1777 [Usaco2010 Hol]rocks 石头木头
  • 原文地址:https://www.cnblogs.com/stelayuri/p/12529118.html
Copyright © 2011-2022 走看看