EXKMP练习题

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/zyszlb2003/article/details/99728979

caioj1462

【题意】
给出26个字母所代表的权值和一个字符串,要求把字符串分成两段(每一段长度至少为1,也就是必须要有字符),假如这一段子串是一个回文串,那么加上该串所有字符权值之和,求最大的权值和。
【输入格式】
输入一个整数T,表示数据组数
每组数据第一行输入26个数,表示26个字母的权值,第二行输入一个字符串(保证字符串内全是小写字母,2<=字符串长度<=500000)
【输出格式】
输出每组数据的最大权值和
【样例输入】
2
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
aba
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
acacac
【样例输出】
1
6

思路

设顺序的字符串为 A A ,倒序的字符串为 B B

题意就是从某个地方断开来嘛。

当前位置为 i i ,在 i i i + 1 i+1 断开,

这时需要判断 A [ 1 i ] = B [ n i + 1 n ] A [ i + 1 n ] = B [ 1 n i ] A[1\sim i]=B[n-i+1\sim n ],A[i+1\sim n]=B[1\sim n-i] ,转化成求例题就好了。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<algorithm>
using namespace std;
const int N=5e5+10;
char a[N],b[N];int ext1[N],ext2[N],nxt[N],n,val[150],ans,sum[N];
void exkmp(char *a,char *b,int *extend)
{
	int x=1;nxt[1]=n;
	while(x<n&&a[x]==a[x+1])++x;
	nxt[2]=x-1;int k=2;
	for(int i=3;i<=n;i++)
	{
		int ed=k+nxt[k]-i,L=nxt[i-k+1];
		if(L<ed)nxt[i]=L;
		else
		{
			x=ed<0?0:ed;
			while(x+i<=n&&a[x+1]==a[x+i])++x;
			nxt[i]=x;k=i;
		}
	}
	x=1;
	while(x<=n&&b[x]==a[x])++x;
	extend[1]=x-1;k=1;
	for(int i=2;i<=n;i++)
	{
		int ed=k+extend[k]-i,L=nxt[i-k+1];
		if(L<ed)extend[i]=L;
		else 
		{
			x=ed<0?0:ed;
			while(x+i<=n&&a[x+1]==b[x+i])++x;
			extend[i]=x;k=i;
		}
	}
}
int main()
{
	int T;scanf("%d",&T);
	while(T--)
	{
		ans=0;
		for(int i='a';i<='z';i++)scanf("%d",&val[i]);
		scanf("%s",a+1);n=strlen(a+1);int m=n;
		sum[0]=0;
		for(int i=1;i<=n;i++)b[m--]=a[i],sum[i]=sum[i-1]+val[a[i]];
		exkmp(a,b,ext1),exkmp(b,a,ext2);
		int tmp=0;
		for(int i=1;i<n;i++)
		{
			ext1[n-i+1]==i?tmp=sum[i]:tmp=0;
			ext2[i+1]==n-i?tmp+=sum[n]-sum[i]:0;
			ans=max(ans,tmp);
		}
		printf("%d\n",ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/zyszlb2003/article/details/99728979