问题 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;
}