题目大意
有一个字符串 s s s,你可以删除若干个字符,删除第 i i i个字符的代价是 c i c_i ci。求删除若干个字符后的字符串中最多能出现多少个 bessie \text{bessie} bessie,并求在 bessie \text{bessie} bessie出现次数最多的前提下最小的删除代价和。
1 ≤ ∣ S ∣ ≤ 2 × 1 0 5 , 1 ≤ c i ≤ 1000 1\leq |S|\leq 2\times 10^5,1\leq c_i\leq 1000 1≤∣S∣≤2×105,1≤ci≤1000
题解
首先,我们可以遍历一遍字符串 S S S来求出最多的出现次数,设这个次数为 a n s 1 ans1 ans1。
设 f i , j f_{i,j} fi,j表示 S S S枚举到前 i i i位,当前最后一个字符串 bessie \text{bessie} bessie比配到第 j j j位时的最小代价。
对于每一个 i i i,用 f i − 1 , j + a i f_{i-1,j}+a_i fi−1,j+ai来更新 f i , j f_{i,j} fi,j,并根据当前的 s i s_i si来进行转移。还要注意当 bessie \text{bessie} bessie中结尾的 e e e转移到新的 bessie \text{bessie} bessie的开头的 b b b时不需要删除中间的字符,所以可以用 l s t lst lst来记录前 i − 1 i-1 i−1个位置中最小的 f k , 6 f_{k,6} fk,6,并用 l s t lst lst来更新 f i , 1 f_{i,1} fi,1。
但是,在一些时候,我们应该选择的是出现次数最多的 f f f值来更新而不是代价最少的。那么,每当转移到一个新的 bessie \text{bessie} bessie的时候,令 f i , 6 = min ( f i , 6 , l s t − 1 0 9 ) f_{i,6}=\min(f_{i,6},lst-10^9) fi,6=min(fi,6,lst−109),这样每多出现一次, f f f值中就多减一个 1 0 9 10^9 109。因为代价无论如何都不会达到 1 0 9 10^9 109,所以这样能保证能够取得出现次数最多且在此前提下代价最小的转移。
注意一开始的 l s t = 1 0 9 lst=10^9 lst=109,最小的删除代价和为 a n s 2 = min { f i , 6 + ( a n s 1 − 1 ) × 1 0 9 } ans2=\min\{f_{i,6}+(ans1-1)\times 10^9\} ans2=min{fi,6+(ans1−1)×109}。
时间复杂度为 O ( n ) O(n) O(n)。
code
#include<bits/stdc++.h>
using namespace std;
int s1,t1,a[200005];
long long inf=1e9,ans1=0,ans2=1e18,lst,f[200005][15];
char s[200005],t[15];
int main()
{
scanf("%s",s+1);
s1=strlen(s+1);
t[1]='b';t[2]='e';t[3]=t[4]='s';t[5]='i';t[6]='e';
t1=6;
for(int i=1;i<=s1;i++){
scanf("%d",&a[i]);
}
for(int i=1,now=1;i<=s1;i++){
if(s[i]==t[now]){
if(now<t1) ++now;
else{
now=1;++ans1;
}
}
}
for(int k=1;k<=6;k++) f[0][k]=inf;
lst=inf;
for(int i=1;i<=s1;i++){
for(int k=1;k<=6;k++) f[i][k]=f[i-1][k]+a[i];
if(s[i]=='b'){
f[i][1]=min(f[i][1],lst-inf);
}
else if(s[i]=='e'){
f[i][2]=min(f[i][2],f[i-1][1]);
f[i][6]=min(f[i][6],f[i-1][5]);
}
else if(s[i]=='s'){
f[i][3]=min(f[i][3],f[i-1][2]);
f[i][4]=min(f[i][4],f[i-1][3]);
}
else if(s[i]=='i'){
f[i][5]=min(f[i][5],f[i-1][4]);
}
lst=min(lst,f[i][6]);
ans2=min(ans2,f[i][6]+(ans1-1)*inf);
}
printf("%lld\n%lld",ans1,ans2);
return 0;
}
文章介绍了一个字符串处理的问题,目标是在给定代价条件下删除字符使子串bessie出现次数最多。通过遍历字符串,使用动态规划方法计算不同位置和状态下的最小代价,同时考虑出现次数的最大化。最终,文章提供了实现代码并讨论了时间复杂度。
316

被折叠的 条评论
为什么被折叠?



