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],val[500100];
 5 char s[500100];
 6 map<char,int> mp;
 7
 8 void Manacher(char str[])
 9 {
10     memset(p,0,sizeof(p));
11     string s="$#";
12     int len=strlen(str);
13     for(int i=0;i<len;i++){
14         s+=str[i];
15         s+=‘#‘;
16     }
17     int mx=0,id=0,reslen=0,rescenter=0;
18     len=s.length();
19     for(int i=1;i<=len;i++){
20         if(mx>i) p[i]=min(p[2*id-i],mx-i);
21         else p[i]=1;
22         while(s[i+p[i]]==s[i-p[i]]) p[i]++;
23         if(mx<i+p[i]){
24             mx=i+p[i];
25             id=i;
26         }
27     }
28 }
29
30 int main()
31 {
32     int t;
33     cin>>t;
34     while(t--){
35         mp.clear();
36         for(int i=0;i<26;i++){
37             int x;
38             cin>>x;
39             mp[‘a‘+i]=x;
40         }
41         cin>>s;
42         int len=strlen(s);
43         for(int i=0;i<len;i++){
44             if(!i) val[i]=mp[s[i]];
45             else val[i]=val[i-1]+mp[s[i]];
46         }
47         int ans=0;
48         Manacher(s);
49         for(int i=1;i<len;i++){
50             int p1=0,p2=0;
51             int x=i*2+1;
52             x=x/2+1;      ///<i的串的中心位置
53             int y=(len-i)*2+1;
54             y=y/2+1;
55             y=(len*2+2)-y;  ///剩下部分的中心位置
56             if(p[x]==x) p1=val[i-1];
57             if(p[y]+y==len*2+2) p2=val[len-1]-val[i-1];
58             ans=max(ans,p1+p2);
59         }
60         cout<<ans<<endl;
61     }
62     return 0;
63 }

②拓展kmp:用原串和反串进行比较,第一次原串做主串,第二次反串做主串。遍历分的位置,如果ex1[i]+i==len,那么说明s中的0~i-1为回文串,如果ex2[len-i]==i,说明s中的i~len-1为回文串,是回文串的价值加上,记录最大的价值。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3
 4 ///next[i]: T[i]到T[m - 1]与T(模式串)的最长相同前缀长度;
 5 ///extend[i]: S[i]到S[n - 1](原串)与T的最长相同前缀长度。
 6
 7 const int maxn=500100;   //字符串长度最大值
 8 int nt[maxn],ex1[maxn],ex2[maxn]; //ex数组即为extend数组
 9 int val[30];
10
11 //预处理计算next数组
12 void GETNEXT(char *str)
13 {
14     int i=0,j,po,len=strlen(str);
15     nt[0]=len;    //初始化nt[0]
16     while(str[i]==str[i+1]&&i+1<len) i++;    //计算nt[1]
17     nt[1]=i;
18     po=1;       //初始化po的位置
19     for(i=2;i<len;i++){
20         if(nt[i-po]+i<nt[po]+po) nt[i]=nt[i-po];    //第一种情况,可以直接得到nt[i]的值
21         else{    //第二种情况,要继续匹配才能得到nt[i]的值
22             j=nt[po]+po-i;
23             if(j<0) j=0;    //如果i>po+nt[po],则要从头开始匹配
24             while(i+j<len&&str[j]==str[j+i]) j++;   //计算nt[i]
25             nt[i]=j;
26             po=i;   //更新po的位置
27         }
28     }
29 }
30
31 //计算extend数组
32 void EXKMP(char *s1,char *s2,int *ex)      ///s1的后缀和s2的前缀匹配
33 {
34     int i=0,j,po,len=strlen(s1),l2=strlen(s2);
35     GETNEXT(s2);    //计算子串的next数组
36     while(s1[i]==s2[i]&&i<l2&&i<len) i++;   //计算ex[0]
37     ex[0]=i;
38     po=0;   //初始化po的位置
39     for(i=1;i<len;i++){
40         if(nt[i-po]+i<ex[po]+po) ex[i]=nt[i-po];      //第一种情况,直接可以得到ex[i]的值
41         else{    //第二种情况,要继续匹配才能得到ex[i]的值
42             j=ex[po]+po-i;
43             if(j<0) j=0;     //如果i>ex[po]+po则要从头开始匹配
44             while(i+j<len&&j<l2&&s1[j+i]==s2[j]) j++;   //计算ex[i]
45             ex[i]=j;
46             po=i;   //更新po的位置
47         }
48     }
49 }
50
51 char s[maxn];
52 int sum[maxn];
53 char p[maxn];
54
55 int main()
56 {
57     int t;
58     cin>>t;
59     while(t--){
60         for(int i=0;i<26;i++)
61             cin>>val[i];
62         cin>>s;
63         int len=strlen(s);
64         for(int i=0;i<len;i++)
65             if(!i) sum[i]=val[s[i]-‘a‘];
66             else sum[i]=val[s[i]-‘a‘]+sum[i-1];
67         strcpy(p,s);
68         reverse(p,p+len);
69         EXKMP(s,p,ex1); //s做主串
70         EXKMP(p,s,ex2); //p做主串
71         int ans=0;
72         for(int i=1;i<len;i++){
73             int ans1=0,ans2=0;
74             if(ex1[i]+i==len) ans1=sum[len-1]-sum[i-1];     //s中的0~i-1;
75             if(ex2[len-i]==i) ans2=sum[i-1];        //s中的i~len-1
76             ans=max(ans,ans1+ans2);
77         }
78         cout<<ans<<endl;
79     }
80     return 0;
81 }

原文地址:https://www.cnblogs.com/lilibuxiangtle/p/12585221.html

时间: 2024-08-05 18:08:43

HDU - 3613 Best Reward(manacher或拓展kmp)的相关文章

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

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

HDU 3613 Best Reward(拓展KMP算法求解)

题目链接: https://cn.vjudge.net/problem/HDU-3613 After an uphill battle, General Li won a great victory. Now the head of state decide to reward him with honor and treasures for his great exploit. One of these treasures is a necklace made up of 26 differe

HDU 4300 Clairewd’s message(初遇拓展KMP)

昨晚一不小心学了拓展KMP,被虐了一晚,最终是这份资料救了我...http://wenku.baidu.com/view/8e9ebefb0242a8956bece4b3.html 说得简单易懂. 然后学了kuangbin的模版: /* * 扩展KMP算法 */ //next[i]:x[i...m-1]与x[0...m-1]的最长公共前缀 //extend[i]:y[i...n-1]与x[0...m-1]的最长公共前缀 void pre_EKMP(char x[],int m,int next[

扩展KMP --- HDU 3613 Best Reward

Best Reward Problem's Link:   http://acm.hdu.edu.cn/showproblem.php?pid=3613 Mean: 给你一个字符串,每个字符都有一个权值(可能为负),让你将这个字符串分成两个字串,使得这两个子串的价值之和最大.一个子串价值的计算方法:如果这个子串是回文串,那么价值就是这个子串所有字符权值之和:否则价值为0. analyse: 经典的扩展KMP算法运用. 假设输入串为s,那么我们首先:strcpy(s1,s)     ;      

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)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=3613 [题目大意] 一个字符串的价值定义为,当它是一个回文串的时候,价值为每个字符的价值的和,如果不是回文串,价值为0,现在给出每种字符的价值.给出一个字符串,要求将其划分为两个子串,要求两个子串的价值和最大. [题解] 求出字符串S的反串T,以T为模板跑一遍S的exkmp就能得到S的后缀是否为回文串的信息,同理以S为模板跑一遍T就可以得到S的前缀是否是回文串的信息,枚举每个断点,取最大值即可.

hdu 3613 Best Reward

Best Reward Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)http://acm.hdu.edu.cn/showproblem.php?pid=3613 Problem Description After an uphill battle, General Li won a great victory. Now the head of state decide to

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