问题 1826: [蓝桥杯][2015年第六届真题]切开字符串

问题 1826: [蓝桥杯][2015年第六届真题]切开字符串

时间限制: 1Sec 内存限制: 128MB 提交: 63 解决: 52

题目描述

Pear有一个字符串,不过他希望把它切成两段。
这是一个长度为N(<=10^5)的字符串。
Pear希望选择一个位置,把字符串不重复不遗漏地切成两段,长度分别是t和N-t(这两段都必须非空)。

Pear用如下方式评估切割的方案:
定义“正回文子串”为:长度为奇数的回文子串。
设切成的两段字符串中,前一段中有A个不相同的正回文子串,后一段中有B个不相同的非正回文子串,则该方案的得分为A*B。

注意,后一段中的B表示的是:“...非正回文...”,而不是: “...正回文...”。
那么所有的切割方案中,A*B的最大值是多少呢?

输入

输入第一行一个正整数N(<=10^5)
接下来一行一个字符串,长度为N。该字符串仅包含小写英文字母。

输出

一行一个正整数,表示所求的A*B的最大值。

样例输入

10
bbaaabcaba

样例输出

38

 思路: 

        正回文子串是长度为奇数的回文子串,它的条件有两个,一是字符串必须是回文串,二是长度为奇数。

        非正回文子串,也有两种情况,一是根本不是回文串,二是长度为偶数的回文串。

        从左到右遍历,记录下每个位置的正回文子串的个数

        从右到左遍历,记录每个位置的非正回文子串的个数,这

        用两个数组分别记录每个位置的正回文子串和非正回文子串的数量,最后求最大值
 

#include<iostream>
#include<algorithm>
#include<set>
using namespace std;
typedef long long ll;
const int N=100000;
bool  judge(string str){//判断是否为回文串 
      string t = str;
	  reverse( t.begin() ,t.end());
	  if( t == str )
  	      return true;
      return false; 
}
int main (){
	int n ;
	string str,temp;
	cin>>n;
	cin>>str;
	ll zheng[N];//用于每个位置存储正回文子串的个数 
	ll fei[N];//用于每个位置存储非正回文子串的个数 
	set<string> e,ne;
	for( int i=0;i<n;i++){//求正回文的个数 
	 	 for(int j=i;j>=0;j-=2){//j-=2 
		    int t=i-j+1;
			temp=str.substr(j,t);
			int flag =judge(temp);
			if(flag)
				e.insert(temp);
		}
		zheng[i]=e.size();
	}
	for (int i=n-1;i>=0;i--){//求非正文子串
	     for(int j=i;j<n;j++){
			//判断是否是正回文子串
			int flag=0;
			int t=j-i+1;
			temp=str.substr(i,t);
			if(temp.size()%2)
				if( e.find(temp)!=e.end())//判断是否在正回文子串的集合里面  
					flag=1;
			if( !flag)
				ne.insert(temp);
		}
		fei[i]=ne.size();
	}
	ll ans=0;
	for(int i=1;i<n;i++)
		ans=max(ans,zheng[i-1]*fei[i]);
	cout<<ans<<endl;
	return 0;
}
发布了761 篇原创文章 · 获赞 134 · 访问量 9万+

猜你喜欢

转载自blog.csdn.net/S_999999/article/details/104100593