HDU 3613 Manacher应用

点击打开链接

题意:上面的数字是26个字母的价值,接下来26个英文字母组成的字符串,将它分成两份,如果分后的串是回文串,则这个串的价值是这个串的所有字母的和,如果不是回文串则这个串价值为0

思路:简单的回文串的变形,先将到每个位置的价值预处理出来然后将字符串跑一边马拉车,我枚举切每个位置的价值和,如现在枚举的是切第三个的位置,则判断一下前三个位置能否形成回文串,那么我们只用判断第二个位置的len1如果等于三则说明是回文串,但是我的代码不是这么实现的,只是说说想法,实现的话是个人的事了,找出最大即可,感觉自己写的找关系那块很麻烦......也没想到能1A,个人感觉数据有点弱

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=500010;
char str[maxn],tmp[maxn<<1];
int len1[maxn<<1];
int init(char *st){
    int len=strlen(st);
    tmp[0]='@';
    for(int i=1;i<=2*len;i+=2){
        tmp[i]='#';
        tmp[i+1]=st[i/2];
    }
    tmp[2*len+1]='#';
    tmp[2*len+2]='$';
    tmp[2*len+3]=0;
    return 2*len+1;
}
int Manacher(char *st,int len){
    int p=0,ans=0,po=0;
    for(int i=1;i<=len;i++){
        if(p>i) len1[i]=min(p-i,len1[2*po-i]);
        else len1[i]=1;
        while(st[i-len1[i]]==st[i+len1[i]]) len1[i]++;
        if(len1[i]+i>p){
            p=len1[i]+i;
            po=i;
        }
        ans=max(ans,len1[i]);
    }
    return ans-1;
}
int num[30],ans[500010];
int main(){
    int T;
    scanf("%d",&T);
    while(T--){
        for(int i=0;i<26;i++) scanf("%d",&num[i]);
        scanf("%s",str);
        int len=strlen(str);
        ans[0]=num[str[0]-'a'];
        for(int i=1;i<len;i++) ans[i]=ans[i-1]+num[str[i]-'a'];
        int len3=init(str);
        int cnm=Manacher(tmp,len3);
        for(int i=1;i<=len3;i++) len1[i]--;
        int ans1=-inf;
        for(int i=1;i<len;i++){
            int t=2*i+1;
            int lmid=(1+t)>>1;
            int rmid=(t+2*len+1)>>1;
            int max1=0;
            if(len1[lmid]*2-1==t-2) max1+=ans[i-1];
            if(len1[rmid]*2-1==2*len-t) max1+=ans[len-1]-ans[i-1];
            ans1=max(ans1,max1);
        }
        printf("%d\n",ans1);
    }
    return 0;
}
时间: 2024-10-09 23:59:46

HDU 3613 Manacher应用的相关文章

HDU 3613(Manacher算法)

题意:字母表的26个字母都有一个价值,给定一个字符串,将该字符串切成两份,对于每一份,如果是回文串,就获得该子串的字母价值之和,否则该子串的价值为0.求出将字符串切成两份后能够获得的最大价值. 做法:先用Manacher算法求出以每个字母为中心的回文串的长度,并计算该字符串的前缀价值和.然后枚举切割点,得到两份子串.这样就可以知道每个子串的中心点,然后检查以该子串的中心点作为中心点的回文串的长度,如果长度等于该子串的长度,那么就加上该子串的价值.然后和最优价值比较就行了. 其实如果熟悉了Mana

Best Reward HDU - 3613(manacher)

Best Reward HDU - 3613 题意:每个小写字母对应有一个价值,给一个小写字母组成的串s,现在要把s切割成两段,如果切割后的串是回文串,那么价值就是该段所有字母的价值之和,问总价值最大多少. 用manacher找到前缀回文和后缀回文,枚举切点更新最大之即可. 1 #include <bits/stdc++.h> 2 using namespace std; 3 const int inf=0x3f3f3f3f; 4 const int maxn=500000+10; 5 cha

HDU - 3613 Best Reward(manacher或拓展kmp)

传送门:HDU - 3613 题意:给出26个字母的价值,然后给你一个字符串,把它分成两个字符串,字符串是回文串才算价值,求价值最大是多少. 题解:这个题可以用马拉车,也可以用拓展kmp. ①Manacher:先记录下第i个字符的价值,然后求前缀和.然后遍历分的位置,分别判断前半段和后半段是否为回文串,是回文串的加上这段的价值(前缀和相减),更新最大价值. 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 int p[1000100],v

HDU 3294 (Manacher) Girls&#39; research

变形的求最大回文子串,要求输出两个端点. 我觉得把'b'定义为真正的'a'是件很无聊的事,因为这并不会影响到最大回文子串的长度和位置,只是在输出的时候设置了一些不必要的障碍. 另外要注意一下原字符串s1中的字符在预处理以后的字符串s2中对应的坐标关系,这样输出的时候就可以照着这个关系转化. 轻松1A,嘿嘿 1 //#define LOCAL 2 #include <iostream> 3 #include <cstdio> 4 #include <cstring> 5

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 5371 Manacher Hotaru&#39;s problem

求出一个连续子序列,这个子序列由三部分ABC构成,其中AB是回文串,A和C相同,也就是BC也是回文串. 求这样一个最长的子序列. Manacher算法是在所有两个相邻数字之间插入一个特殊的数字,比如-1, Manacher算法跑完之后,就计算出每个数字为中心的回文子序列的最大长度 由题意可以知道,AB和BC必然是长度为偶数的回文串.所以我们枚举回文串的中心就枚举相邻两个数字之间的缝隙,也就是那些-1 把AB中间的间隙叫做左中心i,BC之间的间隙叫做右中心j,那么如果两个中心的范围能够互相覆盖,那

HDU 3613 Best Reward 正反两次扩展KMP

题目来源:HDU 3613 Best Reward 题意:每一个字母相应一个权值 将给你的字符串分成两部分 假设一部分是回文 这部分的值就是每一个字母的权值之和 求一种分法使得2部分的和最大 思路:考虑扩展KMP 输出a串 得到a的反串b 求出f[0]和f[1] 和 extend[0]和extend[1] 正反求2次 枚举位置i 分成2部分0到i-1 和i到n-1 由于分成的2部分必须组成原字符串 就是不能多也不能少 那么推断i+extend[i]是否等于n 等于说明i到n-1这个部分是回文串

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 3613 Best Reward(求前后缀回文 拓展KMP or Manacher)

题目大意: 给个字符串X,要把X分成两段T1,T2,每个字母都有一个对应的价值,如果T1,T2是回文串(从左往右或者从右往左读,都一样),那么他们就会有一个价值,这个价值是这个串的所有字母价值之和,如果不是回文串,那么这串价值就为0.问最多能获得多少价值? 思路: 把字符串X逆序后得到字符串Y 让X去匹配Y ,匹配的长度满足extend[i] + i == len,  len=|X|.    的那么X与y的匹配部分是回文串,这不难理解,画图即可 总复杂度是O(n),由于这是求前缀和后缀的回文,用