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

    题目大意

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

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

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

    数据范围

    数据组数不超过 1e5

    字符串的总共长度不超过 1e6


    解题思路

    (标准做法应该是哈希)

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

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

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

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

    (上面这步O(n)不能省略)


    但是因为数据范围内的字符数量很大,所以不能继续采用Easy版的O(n^2)暴力法

    很容易想到,对于中间剩下的子串,要想求出与两边相邻的最长回文串

    就可以用Manacher算法来 O(n) 处理与计算

    在初始化函数里传入两个变量 l 和 r ,表示只要处理 [ l , r ] 区间内的字符即可

    void initStr(int l,int r){
    	int k=0;
    	str[k++]='@';
    	for(int i=l;i<=r;i++){
    		str[k++]='#';
    		str[k++]=s[i];
    	}
    	str[k++]='#';
    	len=k;
    	str[k]='';
    }
    

    在Manacher处理过程中,计算出一个Len值就可以判断一次是不是与左或者与右相邻

    void manacher(){
    	int mx=0,id=0;
    	for(int i=1;i<len;i++){
    		if(mx>i)
    			Len[i]=min(mx-i,Len[2*id-i]);
    		else
    			Len[i]=1;
    		while(str[i+Len[i]]==str[i-Len[i]])
    			Len[i]++;
    		if(Len[i]+i>mx){
    			mx=Len[i]+i;
    			id=i;
    		}
    		
    		if(i==Len[i])//说明此时这个回文串左相邻
    			if(TP<Len[i])
    				TP=Len[i]-1,GR=1;
    		if(i+Len[i]==len)//说明此时这个回文串右相邻
    			if(TP<Len[i])
    				TP=Len[i]-1,GR=2;
    	}
    }
    

    上面的代码中,TP表示最长回文串长度,GR为1表示左相邻,2表示右相邻


    最后输出左+中+右即可





    完整代码

    (77ms / 2000ms)

    #include<bits/stdc++.h>
    using namespace std;
    const int MAXN=1e6+50;
    
    string s;
    char str[MAXN*2];
    int Len[MAXN*2],len,TP,GR;
    
    void initStr(int l,int r){
    	int k=0;
    	str[k++]='@';
    	for(int i=l;i<=r;i++){
    		str[k++]='#';
    		str[k++]=s[i];
    	}
    	str[k++]='#';
    	len=k;
    	str[k]='';
    }
    
    void manacher(){
    	int mx=0,id=0;
    	for(int i=1;i<len;i++){
    		if(mx>i)
    			Len[i]=min(mx-i,Len[2*id-i]);
    		else
    			Len[i]=1;
    		while(str[i+Len[i]]==str[i-Len[i]])
    			Len[i]++;
    		if(Len[i]+i>mx){
    			mx=Len[i]+i;
    			id=i;
    		}
            
    		if(i==Len[i])
    			if(TP<Len[i])
    				TP=Len[i]-1,GR=1;
    		if(i+Len[i]==len)
    			if(TP<Len[i])
    				TP=Len[i]-1,GR=2;
    	}
    }
    
    void solve()
    {
    	cin>>s;
    	int LEN=s.size();
    	
    	int L=0,R=LEN-1;
    	while(L<R&&s[L]==s[R])
    		L++,R--;
    	
    	if(L>=R)
    	{
    		cout<<s<<'
    ';
    		return;
    	}
    	
    	initStr(L,R);
    	TP=0;
    	manacher();
    	for(int i=0;i<L;i++)
    		cout<<s[i];
    	if(GR==1)
    	{
    		for(int i=L,j=0;j<TP;i++,j++)
    			cout<<s[i];
    	}
    	else
    	{
    		for(int i=R-TP+1;i<=R;i++)
    			cout<<s[i];
    	}
    	for(int i=R+1;i<LEN;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;
    }
    
  • 相关阅读:
    微信小程序
    如何在微信小程序中使用骨架屏
    Nlog打印日志到Influxdb数据库
    C#通过模板导出Word的两种方法(超简单)
    VS2019制作的安装包,默认安装到C盘快捷方式无法打开
    orcale数据库还原备份
    Thread 类创建线程
    Quartz.NET
    DataTable ,使用详细。
    Unity3D 学习
  • 原文地址:https://www.cnblogs.com/stelayuri/p/12529117.html
Copyright © 2011-2022 走看看