zoukankan      html  css  js  c++  java
  • 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]='';
     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
    ",Solve());
    105     }
    106     return 0;
    107 }
    View Code
  • 相关阅读:
    forEach 终止循环
    js 解决引用赋值修改新数组导致原数组跟着改变的问题
    es6判断数组是否包含某个元素
    tab css 切换效果
    js对象赋值影响原对象
    小程序返回上个页面 修改上个页面的数据
    小程序 scroll-view scroll-x 不生效
    proxy跨域处理
    常用Dos操作指令
    django全文检索
  • 原文地址:https://www.cnblogs.com/violet-acmer/p/10539141.html
Copyright © 2011-2022 走看看