zoukankan      html  css  js  c++  java
  • 鏖战字符串

    Abwad在nbc即将完成她的程序的时候,急中生智拔掉了她电脑的电源线,争取到了宝贵的时间。作为著名论文《论Ctrl-C与Ctrl-V在信息学竞赛中的应用》的作者,他巧妙地使用了这种上古秘术,顺利扳回一城。
    在决胜局中,Abwad决定和nbc鏖战字符串,比的是谁能更快地将一个“量子态的字符串”删除。“量子态的字符串”的每个字符都有一个删除难度dif[i]。“量子态的字符串”非常顽固,只能先分割成若干个子串,然后再通过以下两种方式删除:
    1、假设子串的所有字符的删除难度之和为x,消耗a*x2+b的时间可以将子串扔进回收站。
    2、若子串中出现次数最多的字符出现的次数不少于l次且不多于r次,那么采用“量子态的py自动机”算法可以消耗c*x+d的时间将子串扔进回收站。
    Abwad自然知道最少用多少时间就能将字符串删去,因此,他希望你求出删去每个前缀[1,i]的最少用时。

    输入

    第一行七个整数n,a,b,c,d,l,r,其中n表示字符串的长度
    第二行一行一个长度为n的字符串
    第三行一行n个整数,表示每个字符的删除难度dif[I]

    输出

    n行,每行一个整数ans,表示删去前缀[1,i]最短的时间

    样例输入

    5 1 3 1 5 1 1 abwad 1 1 1 1 1

    样例输出

    4 7 8 12 13

    提示

    【样例解释】

    以前缀[1,n]为例,将串分为a、bwad两个子串,用方法1删去第一个子串,用方法2删去第二个子串,用时1*1+3+1*4+5=13



    测试点编号

    n

    特殊约定

    1

    n≤10

    所有的字母都是a

    2

    所有的字母都是a或b

    3

     

    4

    5

    n≤2000

    所有的字母都是a

    6

    所有的字母都是a或b

    7

    l=1,r=n

    8

     

    9

    10

    11

    n≤100000

    l=1,r=n

    12

    13

    14

    15

    l>r

    16

    17

     

    18

    19

    20

    对于所有的数据,满足n≤100000,1≤a,b,c,d≤233,1≤l,r≤n,dif[i]≤50,所有字符由小写字母组成。

    【后记】

    在Abwad和nbc同时将最后一个子串删去时,一个带着黑色方框眼镜,方脸,穿着高腰裤的长者,乘着圣洁的祥云,飞进了YYHS的机房。在他伟大的思想的启发下,Abwad和nbc终于放下了对名利的追逐,找到了人生的意义——吃吃吃。从此,他们过上了幸福快乐的生活……
     
    题解:这道题目,当时考试的时候没有过,打了50分,貌似连斜率优化都没有拿10分,错了,不知道为什么。
    所以总结了一下斜率优化,下次是真的不能再错了。
      转移的方式有两种
    1. 没有限制的转移ax^2+b,这个转移,而且是连续的,那么就是一道斜率优化的裸题,对吧。
    2. 通过cx+b转移,这里为什么降了一次,这里是有原因的,这样维护的就是满足条件的最小值就可以了,dp[j]-c*sum[j]<=dp[k]-c*sum[k]。

      所以就发现,维护dp[j]-c*sum[j]为关键字的最小值,然后剩下的就是如何判断是否合法,然后就没有了,如何判断呢?

      就是记录一个前缀和,因为N为十万,那么最多有26个不同的字符,就开一个26*100000空间的数组,记录前缀和,然后每次26的复杂度

      去判断合不合法,这样用堆或者单调队列维护最小值,就OK了。

    我这里视同优先队列的。

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cmath>
     4 #include<cstring>
     5 #include<iostream>
     6 #include<queue>
     7 #define LL long long
     8 #define fzy pair<LL,int>
     9 #define N 100007
    10 #define inf 1e9+7
    11 
    12 using namespace std;
    13 
    14 int n,a,b,c,d,l,r;
    15 int qz[N][27],q[N];
    16 LL sum[N],dp[N];
    17 char ch[N];
    18 
    19 priority_queue<fzy,vector<fzy>,greater<fzy> >st;
    20 LL get_x(int k,int j)
    21 {
    22     return dp[j]-dp[k]+a*sum[j]*sum[j]-a*sum[k]*sum[k];
    23 }
    24 LL get_y(int k,int j)
    25 {
    26     return 2*a*(sum[j]-sum[k]);
    27 }
    28 bool pan(int x,int y)
    29 {
    30     int res=-inf;
    31     for (int i=0;i<26;i++)
    32         res=max(res,qz[y][i]-qz[x][i]);
    33     if (res<=r&&res>=l) return true;
    34     else return false;
    35 }
    36 int main()
    37 {
    38 //    freopen("1.in","r",stdin);
    39 //    freopen("fzy.out","w",stdout);
    40     
    41     scanf("%d%d%d%d%d%d%d",&n,&a,&b,&c,&d,&l,&r);
    42     scanf("%s",ch+1);
    43     int head=0,tail=0,id=0;
    44     q[0]=0;
    45     for (int i=1;i<=n;i++)
    46     {
    47         scanf("%d",&sum[i]);
    48         for (int j=0;j<26;j++) qz[i][j]=qz[i-1][j];
    49         qz[i][ch[i]-'a']++;
    50             
    51         sum[i]+=sum[i-1];
    52         while (head+1<=tail&&(LL)get_x(q[head],q[head+1])<=(LL)get_y(q[head],q[head+1])*sum[i]) head++;
    53         int t=q[head];
    54         dp[i]=dp[t]+a*(sum[i]-sum[t])*(sum[i]-sum[t])+b;
    55         
    56         while (id<=i) 
    57             if (pan(id,i))
    58             {
    59                 st.push(make_pair(dp[id]-c*sum[id],id));
    60                 id++;
    61             }
    62             else break;
    63         while(!st.empty())
    64         {
    65             fzy now=st.top();
    66             t=now.second;
    67             if (pan(t,i))
    68             {
    69                 dp[i]=min(dp[i],dp[t]+c*(sum[i]-sum[t])+d);
    70                 break;
    71             }
    72             else
    73             {
    74                 st.pop();
    75                 continue;
    76             }
    77         }
    78         
    79         while (head+1<=tail&&(LL)get_x(q[tail-1],q[tail])*get_y(q[tail],i)>=(LL)get_x(q[tail],i)*get_y(q[tail-1],q[tail])) tail--;
    80         q[++tail]=i;
    81         printf("%lld
    ",dp[i]);
    82     }
    83 }
  • 相关阅读:
    面试题38:股票最大收益问题
    面试题37:字符串中的括号
    面试题36:罗马数和阿拉伯数的相互转换
    面试题35:大数(字符串)相乘
    面试题34:文本对齐
    面试题33:简化目录路径
    面试题32:字符串的通配符匹配
    并发调度的可串行性
    mysql limit查询(分页查询)探究
    通过宏定义将__declspec(dllexport)与__declspec(dllimport)的转化,实现库代码和使用代码使用同一份头文件
  • 原文地址:https://www.cnblogs.com/fengzhiyuan/p/7537792.html
Copyright © 2011-2022 走看看