鏖战字符串
Posted Kaiser
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了鏖战字符串相关的知识,希望对你有一定的参考价值。
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分,错了,不知道为什么。
所以总结了一下斜率优化,下次是真的不能再错了。
转移的方式有两种
- 没有限制的转移ax^2+b,这个转移,而且是连续的,那么就是一道斜率优化的裸题,对吧。
- 通过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 }
以上是关于鏖战字符串的主要内容,如果未能解决你的问题,请参考以下文章
鏖战九载,Google 是否会因 Oracle 而弃用 Java?