题解:P9190 [USACO23OPEN] Pareidolia G
首先第一问可以贪心解决,从前往后能匹配尽量匹配。
考虑一个暴力的DP。
记
然后转移有几种:
-
考虑从
i 开始构造这个连续子串,前面[1,i] 都不算了。f(i,0)=0 。 -
考虑匹配一个字符,如果可以匹配。
f(i,j'+1)\gets f(i-1,j') -
考虑截断。
f(i,j,0)\gets f(i-1,j,k) 。截断操作的作用其实是使得连续子串中间允许其它字符出现。
-
考虑删除。
f(i,j')\gets f(i-1,j') 。
状态数是
对于每个前缀
我们可以考虑对每个后缀倒着贪心一遍,这样可以求出一个对应的最大匹配长度
然后记
那么,
于是状态数变为
:::info[Code]
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N=200005;
namespace Fastio{
#define SIZIO (1<<22)
#define gc() (rp1==rp2&&(rp2=(rp1=buf)+fread(buf,1,SIZIO,stdin))==rp1?EOF:*rp1++)
char buf[SIZIO+1],*rp1,*rp2;
inline int read(){
int d=0,f=0;char ch=gc();
while (!isdigit(ch)) f|=(ch=='-'),ch=gc();
while (isdigit(ch)) d=(d<<1)+(d<<3)+ch-'0',ch=gc();
return f?-d:d;
}
inline void read(char &c){c=gc();while(c<33||c>126) c=gc();}
inline void read(char *s){
char ch=gc();
while(ch<33||ch>126)ch=gc();
while(ch>=33&&ch<=126) (*s++)=ch,ch=gc();
*s=0;
}
};using namespace Fastio;
char s[]={'b','e','s','s','i','e'},S[N];
int f[N][7],n,a[N],g[N],l[N];
inline void cmin(int &x,int y){(x>y)&&(x=y);}
bool is(int i,int j){return j-l[i]>=0&&j-l[i]<=5;}
signed main(){
read(S+1),n=strlen(S+1);
for (int i=1;i<=n;i++) a[i]=read();
g[n]=0;
for (int i=n,j=5,k=0;i>=1;i--){
if (S[i]==s[j]) j--,k++;
g[i-1]=k;if (j==-1) j=5;
}
int tot=g[0]/6,ans=1e9;l[0]=6*tot-g[0];
for (int i=0;i<=n;i++)
for (int j=0;j<=6;j++) f[i][j]=1e9;
if (is(0,0)) f[0][0-l[0]]=0;
for (int i=1;i<=n;i++){
l[i]=6*tot-g[i];
if (is(i,0)) f[i][0-l[i]]=0;
for (int j=max(6*tot-g[i-1],0),up=6*(tot+1)-g[i-1]-1;j<=up;j++){
if (is(i,j)) cmin(f[i][j-l[i]],f[i-1][j-l[i-1]]+a[i]);
if (is(i,j/6*6)) cmin(f[i][j/6*6-l[i]],f[i-1][j-l[i-1]]);
if (is(i,j+1)&&S[i]==s[j%6]) cmin(f[i][j-l[i]+1],f[i-1][j-l[i-1]]);
}
if (is(i,tot*6)) ans=min(ans,f[i][6*tot-l[i]]);
}
printf("%d\n%d\n",tot,ans);
return 0;
}
:::