• 回文(牛客 https://ac.nowcoder.com/acm/problem/17062)


    链接:https://ac.nowcoder.com/acm/problem/17062
    来源:牛客网

    题目描述:

    字符串 S 只包含小写英文字母。有四种操作,每次操作你可以选择其中一种:

    删除字符串的第一个字母。

    删除字符串的最后一个字母。
    在字符串的头部添加任意一个你想要的字母。
    在字符串的尾部添加任意一个你想要的字母。
    删除一个第 i 种英文字母需要的花费是 Ai,添加一个第 i 种英文字母的花费是 Bi
    请问将字符串 S 变成回文串需要的最小花费是多少?

    输出描述:

    输出一个正整数,表示把字符串 S 变成一个回文串的最小花费。

    具体思路:

    首先分析操作类型,只能在头部和尾部进行操作,换个方法也就是说只能对这个串的前缀和后缀进行操作。

    所以对于每一个位置,找出以当前这个位置的最长回文串,然后这个回文串区间我们就停止操作了。开始对1~l-1和 r+1~len这两段区间进行操作使得整个串变成回文串。

    然后再继续往下想,对于每一个前缀(1 ~ l-1),我们可以把它全部删除;也可以删除一部分,在字符串的另一侧再填上未删除的部分,使得总体在回文串的基础上再构成一个回文串,后缀同理。也就是说对于每一次的操作,我们是将这个回文串的一侧删除,然后通过另一侧的情况来调整被删除的回文串一侧。

    按照这个思路,我们可以统计一下对于当前这个前缀,从哪里开始删除,是最节省的,并且保存一下最小花费。后缀做同样的处理,然后每一次枚举这个回文串的位置就好了。

    AC代码:

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 # define inf 0x3f3f3f3f
      4 # define ll_inf (1ll<<60)
      5 # define ll long long
      6 const int maxn = 2e5+100;
      7 char str[maxn],A[maxn<<1];
      8 int pre[maxn<<1],B[maxn<<1];
      9 ll del[30],add[30];
     10 void manacher(char s[],int len){
     11 //cout<<s+1<<endl;
     12 int l=0;
     13 A[l++]='$';
     14 A[l++]='#';
     15 for(int i=0;i<len;i++){A[l++]=s[i+1];A[l++]='#';}
     16 A[l]=0;
     17 //cout<<A+1<<endl;
     18 int mx=0,id=0;
     19 for(int i=0;i<l;i++){
     20 B[i]= mx > i ? min(B[2*id-i],mx-i):1;
     21 while(A[i+B[i]]==A[i-B[i]])B[i]++;
     22 if(i+B[i]>mx){
     23 mx=i+B[i];
     24 id=i;
     25 }
     26 }
     27 }
     28 ll pre_del[maxn],pre_add[maxn];// 将当前前缀删除的花费;将当前前缀增加的花费
     29 ll suf_del[maxn],suf_add[maxn];// 将当前后缀删除的花费;将当前后缀增加上的花费
     30 ll pre_cost[maxn],suf_cost[maxn]; // 对于当前的前缀,调整这一段,使得整个字符串前缀不影响构成回文串的最小花费,后缀同理
     31 void init(int len){
     32 //pre_del[0]=del[str[0]-'a'];
     33 for(int i=1;i<=len;i++){pre_del[i]=pre_del[i-1]+del[str[i]-'a'];}
     34 //pre_add[1]=add[str[1]-'a'];
     35 for(int i=1;i<=len;i++){pre_add[i]=pre_add[i-1]+add[str[i]-'a'];}
     36 //suf_del[len-1]=del[str[len-1]-'a'];
     37 for(int i=len;i>=1;i--){suf_del[i]=suf_del[i+1]+del[str[i]-'a'];}
     38 //suf_add[len-1]=add[str[len-1]-'a'];
     39 for(int i=len;i>=1;i--){suf_add[i]=suf_add[i+1]+add[str[i]-'a'];}
     40 
     41 int pos=0;
     42 for(int i=1;i<=len;i++){
     43 if(pre_del[pos]+pre_add[i]-pre_add[pos]<pre_del[i]){
     44 pre_cost[i]=pre_del[pos]+pre_add[i]-pre_add[pos];
     45 }
     46 else {pos=i;pre_cost[i]=pre_del[i];}
     47 }
     48  pos=len+1;
     49 for(int i=len;i>=1;i--){
     50 if(suf_del[pos]+suf_add[i]-suf_add[pos]<suf_del[i]){
     51 suf_cost[i]=suf_del[pos]+suf_add[i]-suf_add[pos];
     52 }
     53 else {pos=i;suf_cost[i]=suf_del[i];}
     54 
     55 }
     56 }
     57 int p[maxn];
     58 int main(){
     59 scanf("%s",str+1);
     60 int len=strlen(str+1);// 本来下标从0开始,发现求pre_cost等数组的时候打起来比较麻烦;
     61 for(int i=0;i<26;i++){
     62 scanf("%lld %lld",&del[i],&add[i]);
     63 }
     64 init(len);
     65 //cout<<str+1<<endl;
     66 manacher(str,len);
     67 ll minn=ll_inf;
     68 //for(int i=0;i<len+len;i++){
     69 //cout<<A[i]<<" "<<B[i]<<endl;
     70 //}
     71 //cout<<pre_del[len]<<endl;
     72 int l,r;
     73 for(int i=1;i<=len+len+2;i++){
     74 if((i&1)){
     75 l=i/2-(B[i]-1)/2;// 之所以是i/2的原因,这个是对于新构成的回文串来说的,长度比原来增加的两倍多
     76 r=i/2+(B[i]-1)/2+1;
     77 }
     78 else {
     79 l=i/2-(B[i]-1)/2-1;
     80 r=i/2+(B[i]-1)/2+1;
     81 }
     82 minn=min(minn,min(pre_del[l]+suf_cost[r],suf_del[r]+pre_cost[l]));
     83 }
     84 printf("%lld
    ",minn);
     85 return 0;
     86 }
     87 /*
     88 jell
     89 1000 1100
     90 350 700
     91 200 800
     92 2000 2000
     93 2000 432
     94 2000 2000
     95 2000 2000
     96 2000 2000
     97 2000 2000
     98 20 2000
     99 2000 2000
    100 350 35
    101 200 800
    102 2000 2000
    103 2000 2000
    104 2000 2000
    105 2000 2000
    106 2000 2000
    107 2000 2000
    108 2000 2000
    109 2000 2000
    110 2000 2000
    111 2000 2000
    112 2000 2000
    113 15 2000
    114 2000 2000
    115 */
  • 相关阅读:
    实验四 决策树算法及应用
    实验三 朴素贝叶斯算法及其应用
    计算机网络概述
    实验二——K近邻
    感知机及其应用
    面向对象设计与分析
    结构化分析和设计
    如何安装Dosbox并运行一个汇编代码
    如何解决从windows下载到ubuntu的中文安装包解压中文名出现乱码的情况
    实验一——visio的使用
  • 原文地址:https://www.cnblogs.com/letlifestop/p/10945680.html
Copyright © 2020-2023  润新知