hdu 3613"Best Reward"(Manacher算法)

传送门

 

题意:

  国王为了犒劳立下战功的大将军Li,决定奖给Li一串项链,这个项链一共包含26中珠子"a~z",每种珠子都有

  相应的价值(-100~100),当某个项链可以构成回文时,那么这个项链的价值就是每个珠子价值的加和,如果

  构不成,那么这个项链的价值就为0;

  求如何将国王奖赏的一串项链拆成价值加和最大的两串项链,求出这个最大价值。

题解:

  本来我是在找有关拓展KMP的相关题目的,百度到一大牛的博客(“扩展KMP题目”),当做到第二个题目的时候,

  思来想去,就是没找到其和拓展KMP的联系,然后,感觉可以用Manacher算法,刷刷刷撸了个Manacher的代码

  提交,AC,所以,我暂且谈谈如何用Manacher算法解这道题;

  ①首先将项链串s[]预处理(了解Manacher算法就理解啥意思了);

  ②准备一个数组sum[],sum[ i ]:预处理后的数组中前 i 个字符对应的价值的加和,'#'当作0;

  ③使用Manacher算法求解出回文半径数组radius[];

  ④假设从 i 位置切割项链,将项链分成[ 0,i ],[ i,len-1 ]两串,分别求解对应的总价值,令ans=max{从i位置分割的总价值}

 AC代码:
  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 using namespace std;
  5 #define INF 0x3f3f3f3f
  6 #define lowbit(x) (x&-x)
  7 #define mem(a,b) memset(a,b,sizeof(a))
  8 const int maxn=5e5+50;
  9 
 10 int val[26];
 11 char s[2*maxn];
 12 char temp[maxn];
 13 int radius[2*maxn];
 14 int sum[2*maxn];
 15 void Trans()
 16 {
 17     int len=strlen(s);
 18     strcpy(temp,s);
 19     for(int i=0;i < len;++i)
 20     {
 21         s[2*i]='#';
 22         s[2*i+1]=temp[i];
 23     }
 24     s[2*len]='#';
 25     s[2*len+1]='\0';
 26 }
 27 void Manacher()
 28 {
 29     mem(radius,0);
 30     int len=strlen(s);
 31     int R=0;
 32     int K=0;
 33     radius[0]=0;
 34     for(int i=1;i < len;++i)
 35     {
 36         int cnt=0;
 37         if(i >= R)
 38         {
 39             while(i+cnt < len && i-cnt >= 0 && s[i+cnt] == s[i-cnt])
 40                 cnt++;
 41             radius[i]=cnt;
 42             if(i+cnt-1 > R)
 43             {
 44                 R=i+cnt-1;
 45                 K=i;
 46             }
 47         }
 48         else
 49         {
 50             int j=K-(i-K);
 51             if(i+radius[j]-1 != R)
 52                 radius[i]=min(R-i+1,radius[j]);
 53             else
 54             {
 55                 cnt=R-i+1;
 56                 while(i-cnt >= 0 && i+cnt < len && s[i-cnt] == s[i+cnt])
 57                     cnt++;
 58                 radius[i]=cnt;
 59                 if(i+cnt-1 > R)
 60                 {
 61                     R=i+cnt-1;
 62                     K=i;
 63                 }
 64             }
 65         }
 66     }
 67 }
 68 int Solve()
 69 {
 70     Trans();//预处理字符串s
 71     Manacher();
 72 
 73     int len=strlen(s);
 74     sum[0]=0;
 75     for(int i=1;i < len;++i)//前缀和
 76         sum[i]=sum[i-1]+(s[i] == '#' ? 0:val[s[i]-'a']);
 77 
 78 
 79     int ans=-INF;
 80     for(int i=1;i < len-2;i+=2)
 81     {
 82         int cnt=0;
 83         int x=(i+1)>>1;//[0,i+1]的中点坐标
 84         if(radius[x] == x+1)//判断[0,i]是否构成回文子串
 85             cnt += sum[i];
 86 
 87         int y=(len+i)>>1;//[i+1,len-1]的中点坐标
 88         if(radius[y] == len-y)//判断[i+1,len-1]是否构成回文子串
 89             cnt += sum[len-1]-sum[i];
 90         ans=max(ans,cnt);
 91     }
 92     return ans;
 93 }
 94 int main()
 95 {
 96 //    freopen("C:/Users/hyacinthLJP/Desktop/stdin/contest","r",stdin);
 97     int test;
 98     scanf("%d",&test);
 99     while(test--)
100     {
101         for(int i=0;i < 26;++i)
102             scanf("%d",val+i);
103         scanf("%s",s);
104         printf("%d\n",Solve());
105     }
106     return 0;
107 }
View Code

 

posted @ 2019-03-15 19:44  HHHyacinth  阅读(182)  评论(0编辑  收藏  举报