HDU 3613(Manacher算法)

题意:字母表的26个字母都有一个价值,给定一个字符串,将该字符串切成两份,对于每一份,如果是回文串,就获得该子串的字母价值之和,否则该子串的价值为0。求出将字符串切成两份后能够获得的最大价值。

做法:先用Manacher算法求出以每个字母为中心的回文串的长度,并计算该字符串的前缀价值和。然后枚举切割点,得到两份子串。这样就可以知道每个子串的中心点,然后检查以该子串的中心点作为中心点的回文串的长度,如果长度等于该子串的长度,那么就加上该子串的价值。然后和最优价值比较就行了。

其实如果熟悉了Manacher算法的应用,这道题是很简单的。

#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<set>
#include<map>
#include<stack>
#include<vector>
#include<queue>
#include<string>
#include<sstream>
using namespace std;

const int maxn=500005;
char str[maxn],s[maxn<<1];
int p[maxn<<1],newlen;
int val[26];
int presum[maxn];

void init(int n)
{
	newlen=n<<1;
	for(int i=0;i<=newlen+1;i++) s[i]='#';
	for(int i=1;i<=n;i++) s[i<<1]=str[i];
	s[newlen+2]=0;
}

void manacher()
{
	int mx=0,id=0;
	for(int i=1;i<=newlen;i++)
	{
		if(mx>i) p[i]=min(p[2*id-i],mx-i);
		else p[i]=1;

		while(i-p[i]>=0&&s[i-p[i]]==s[i+p[i]]) p[i]++;
		if(i+p[i]>mx)
		{
			mx=i+p[i];
			id=i;
		}
	}
}
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		for(int i=0;i<26;i++) scanf("%d",&val[i]);
		scanf("%s",str+1);
		int len=strlen(str+1);
		presum[0]=0;
		for(int i=1;i<=len;i++) presum[i]=presum[i-1]+val[str[i]-'a'];

		init(len);
		manacher();
		int ans=-(INT_MAX-1);

		for(int cutpnt=1;cutpnt<len;cutpnt++)
		{
			int temp=0;
			int len1=cutpnt,len2=len-len1;
			//看子串的长度的奇偶性
			if(len1%2==1)
			{
				int midpnt=len1/2+1;
				int palen=p[midpnt*2]-1;
				if(midpnt-palen/2==1) temp+=presum[len1];
			}
			else
			{
				int midpnt=len/2;
				int palen=p[midpnt*2+1]-1;
				if(midpnt-palen/2+1==1) temp+=presum[len1];
			}

			if(len2%2==1)
			{
				int midpnt=len1+len2/2+1;
				int palen=p[midpnt*2]-1;
				if(midpnt+palen/2==len) temp+=presum[len]-presum[len1];
			}
			else
			{
				int midpnt=len1+len2/2;
				int palen=p[midpnt*2+1];
				if(midpnt+palen/2==len) temp+=presum[len]-presum[len1];
			}
			if(temp>ans) ans=temp;
		}
		printf("%d\n",ans);
	}
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-05 20:03:37

HDU 3613(Manacher算法)的相关文章

hdu 3068 Manacher算法 O(n)回文子串算法

题目:http://acm.hdu.edu.cn/showproblem.php?pid=3068 关于算法的教程  推荐这个:http://blog.csdn.net/ggggiqnypgjg/article/details/6645824    注意:我推荐的这篇博客里说的那个代码有bug,我觉得没问题,而是博主在用的时候写错了,博主举得反例我都过了 而且hdu 3068也过了 最开始是用的后缀数组,2000ms+ 果断超时............... 看过一遍很快就学会这个算法了:然后A

hdu 3068 Manacher算法

题意:求最长回文串,模板题 1 #include<cstdio> 2 #include<iostream> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 #include<queue> 7 #include<map> 8 using namespace std; 9 #define MOD 1000000007 10 const int INF=

HDU 3613 Manacher应用

点击打开链接 题意:上面的数字是26个字母的价值,接下来26个英文字母组成的字符串,将它分成两份,如果分后的串是回文串,则这个串的价值是这个串的所有字母的和,如果不是回文串则这个串价值为0 思路:简单的回文串的变形,先将到每个位置的价值预处理出来然后将字符串跑一边马拉车,我枚举切每个位置的价值和,如现在枚举的是切第三个的位置,则判断一下前三个位置能否形成回文串,那么我们只用判断第二个位置的len1如果等于三则说明是回文串,但是我的代码不是这么实现的,只是说说想法,实现的话是个人的事了,找出最大即

hdu 3294 manacher算法

没什么还说的  也就是这一类的裸题吧 #include<stdio.h> #include<string.h> #include<iostream> using namespace std; char str[200010],str1[400010]; int mark[400010]; int min(int a,int b) { return a<b?a:b; } int main() { char str2[5]; int i,j; while(~scanf

HDU 3616 Best Reward (Manacher算法 前缀回文+后缀回文)

Best Reward Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 785    Accepted Submission(s): 338 Problem Description After an uphill battle, General Li won a great victory. Now the head of state

HDU 3613 Best Reward(manacher求前、后缀回文串)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3613 题目大意: 题目大意就是将字符串s分成两部分子串,若子串是回文串则需计算价值,否则价值为0,求分割字符串s能获得的最大价值. 解题思路: 用manacher算法计算出p[i],每次计算p[i]是顺便计算一下这段回文串是否能到达边界,若能则计算出前缀或者后缀的结束位置,标记起来.//还有之前数组开1e6+5教C++是错的,改成2e6+5就对了,不觉明历.... 代码 1 #include<ios

HDU 3068 最长回文 (manacher算法)

最长回文 Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 9188    Accepted Submission(s): 3159 Problem Description 给出一个只由小写英文字符a,b,c...y,z组成的字符串S,求S中最长回文串的长度. 回文就是正反读都是一样的字符串,如aba, abba等 Input 输入有多组

HDU 3294 Girls&#39; research (Manacher算法 + 记录区间)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3294 题目大意:输入一个字符ch和一个字符串,问如果把ch当作'a'的话,字符串的每个字符也要做相应变化,如b aa,若b为'a',则b前面的a就为'a'前面的'z',这里是循环表示,输出字符串的最长回文子串,如果最长回文子串串长为1,输出No solution! 几乎是模板题,唯一的特别之处就是要输出回文串字符,所以要记录max(Mp[i])对应的在原串中的字符区间,根据Manacher算法的步骤

HDU Hotaru&#39;s problem(Manacher算法+贪心)

manacher算法详见 http://blog.csdn.net/u014664226/article/details/47428293 题意:给一个序列,让求其最大子序列,这个子序列由三段组成,第一段和第二段对称,第一段和第三段一样. 思路:首先利用Manacher算法求出以任意两个相邻元素为中心的回文串长度,用a[i]表示i-1,i为中心的回文串长度的一半, 那么问题就转化成了求最大的x,使得a[i]>=x,a[i+x]>=x,这一步可以贪心来做. 将a[i]从大到小排序(间接排序保留