码迷,mamicode.com
首页 > 其他好文 > 详细

鏖战字符串

时间:2017-09-17 22:23:09      阅读:252      评论:0      收藏:0      [点我收藏+]

标签:sum   scan   记录   前缀   scanf   pre   logs   电源   style   

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\n",dp[i]);
82     }
83 }

 

鏖战字符串

标签:sum   scan   记录   前缀   scanf   pre   logs   电源   style   

原文地址:http://www.cnblogs.com/fengzhiyuan/p/7537792.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!