首页 > 其他分享 >鏖战字符串

鏖战字符串

时间:2022-11-22 21:03:06浏览次数:54  
标签:子串 int ++ 字符串 while 鏖战 dp


C: 鏖战字符串

时间限制: 1 Sec  内存限制: 128 MB

题目描述


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

1

2

1

3


提示

【样例解释】 

以前缀[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终于放下了对名利的追逐,找到了人生的意义——吃吃吃。从此,他们过上了幸福快乐的生活……

当n≤2000

令dp[i]表示删去前缀[1,i]的最小代价。

dp[i]=min(dp[j]+a*sum[j~i]^2+b,dp[j]+c*sum[j~i]+d)

第二种转移暴力判断是否合法即可。

当l>r即第二种转移不存在。

dp[i]=min(dp[j]+a*sum[j~i]^2+b),是一个分段平方和

用单调队列优化转移即可。

考虑方案二的转移。

首先是出现字母次数的限制,用单调队列乱搞/倍增都可以。

也就是说方案二强制从一个区间中转移。

d+s[i]*c

后面红色的是常数,那么只要维护区间dp[j]-s[j]*c的最小值即可

可以用数据结构,但是因为区间的左右端点具有单调性,单调队列也可以。


#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int M=500010;
int n,a,b,c,d,l0,r0,i,h[M],H[M],cntl[110],cntr[110];
ll s[M],dp[M];
char S[M];
int calc(int j,int k,int i){
return (dp[k]-dp[j]+s[k]*s[k]*a-s[j]*s[j]*a)*(s[i]-s[k])>=(dp[i]-dp[k]+s[i]*s[i]*a-s[k]*s[k]*a)*(s[k]-s[j]);
}
ll read(){
ll x=0;char ch=getchar();
while (ch<'0'||ch>'9')ch=getchar();
while (ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
return x;
}
int main(){
scanf("%d%d%d%d%d%d%d",&n,&a,&b,&c,&d,&l0,&r0);
scanf("%s",S+1);
for (i=1;i<=n;i++)s[i]=read(),s[i]+=s[i-1];
int l=1,r=1,L=1,R=0,nowl=1,nowr=0;
for (i=1;i<=n;i++){
while (l<r&&(s[h[l+1]]-s[h[l]])*s[i]*a*2>=dp[h[l+1]]-dp[h[l]]+s[h[l+1]]*s[h[l+1]]*a-s[h[l]]*s[h[l]]*a)l++;
dp[i]=dp[h[l]]+(s[i]-s[h[l]])*(s[i]-s[h[l]])*a+b;
cntl[S[i]-'a']++;cntr[S[i]-'a']++;
while (cntl[S[i]-'a']>r0){
cntl[S[nowl]-'a']--;
nowl++;
while(L<=R&&H[L]+1<nowl)L++;
}
while (cntr[S[i]-'a']>=l0){
if (nowr){
cntr[S[nowr]-'a']--;
if (cntr[S[i]-'a']<l0){
cntr[S[nowr]-'a']++;
break;
}
}
while (L<=R&&dp[nowr]-s[nowr]*c<=dp[H[R]]-s[H[R]]*c)R--;
H[++R]=nowr;
nowr++;
}
if (L<=R)dp[i]=min(dp[i],dp[H[L]]+(s[i]-s[H[L]])*c+d);
while (l<r&&calc(h[r-1],h[r],i))r--;
h[++r]=i;
printf("%lld\n",dp[i]);
}
}

标签:子串,int,++,字符串,while,鏖战,dp
From: https://blog.51cto.com/u_15888102/5878484

相关文章

  • JS前期数组、字符串、时间、定时器、DOM\BOM事件方法等总结
    1.字符串方法        .charAt(对应字符元素下标)——根据下标查找字符串内元素        .charCodeAt(对应字符元素下标)——根据下标查找字符串某元素在u......
  • 第五节、字符串
    第五节、字符串第一节基础知识1.每个字符都有对应的整数ASCII码,常用ASCII值,’A''Z'是6590,‘a''z'是97122,’0‘’9'是4857,字符可以参与运算,运算时会将其当作整数。(记住)......
  • 字符串
    字符串比较          字符串理解       ......
  • 20221122-Python格式化字符串
    1.格式化字符串       ......
  • FileReader之获取文本文件内容为字符串
    FileReader之获取文本文件内容为字符串FileReader官网描述:FileReader对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用File或Blob......
  • C语言字符串
    文章目录​​一、字符串的概念​​​​二、占用内存的情况​​​​三、字符串的初始化​​​​四、字符串与指针​​​​五、字符串的结尾标志​​​​六、字符串的输出​​......
  • Newtonsoft的高级玩法,让你的json字符串与众不同
    json一经出现就得到多很多开发员的青睐,数据传输直接取代了之前的xml格式,不过也确实非常好用。关于json的常用操作,可以参考这篇文章。今天要分享的是Newtonsoft这个类库对Js......
  • PostgreSQL常用字符串分割函数整理记录
    记录一下postgresql字符串切割处理的函数1.SPLIT_PARTSPLIT_PART()函数通过指定分隔符分割字符串,并返回第N个子串。语法:SPLIT_PART(string,delimiter,position)st......
  • 字符串中的第一个唯一字符
    字符串中的第一个唯一字符一、题目描述给定一个字符串s,找到它的第一个不重复的字符,并返回的所有。如果不存在,则返回-1。示例1输入:s="leetcode"输出:0示例2输......
  • 【华为OJ12】字符串反转
    题目描述写出一个程序,接受一个字符串,然后输出该字符串反转后的字符串。例如:importjava.util.Scanner;publicclassMain{publicstaticStringreverseStr(String......