题目暂缺
题解:
DP。
首先,定义
f
[
i
]
f[i]
f[i]表示使完全在
i
i
i之前的子串都合法时的最小代价。
这样定义,状态还不能直接转移。
考虑贪心。
可知,对于所有以
i
i
i结尾的子串,起点为
k
k
k,
f [ i ] = m i n ( f [ j − 1 ] + a [ j ] ) m a x ( k ) ≤ j ≤ i f[i]=min(f[j-1]+a[j])_{max(k)\leq j\leq i} f[i]=min(f[j−1]+a[j])max(k)≤j≤i
但是这样会不满足后效型,即可能 m a x ( k ) max(k) max(k) 比之前的子串起点小,且所选的 j j j不在子串中。
所以我们要让候选子集不超过产生后效型的部分。
定义
l
i
m
i
t
[
i
]
limit[i]
limit[i] 表示已出现过的子串的最大起点。这样既可满足。
这时我们的转移方程修改如下:
l
i
m
i
t
[
i
]
=
m
a
x
(
l
i
m
i
t
[
i
−
1
]
,
m
a
x
(
k
)
)
limit[i]=max(limit[i-1],max(k))
limit[i]=max(limit[i−1],max(k))
f
[
i
]
=
m
i
n
(
f
[
j
−
1
]
+
a
[
j
]
)
l
i
m
i
t
[
i
]
≤
j
≤
i
f[i]=min(f[j-1]+a[j])_{limit[i]\leq j \leq i}
f[i]=min(f[j−1]+a[j])limit[i]≤j≤i
判断子串时用 H a s h Hash Hash,转移用线段树维护既可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#define N 200005
using namespace std;
const unsigned long long P=13331;
long long f[N],a[N],n,m,len[12],lim[N];
unsigned long long hs[12],p[N],g[N];
struct segment
{
long long minn,l,r;
}t[N<<2];
void build(long long p,long long l,long long r){
t[p].l=l;t[p].r=r;t[p].minn=0;
if(l==r)return ;
long long mid=(l+r)>>1;
build(p<<1,l,mid);build(p<<1|1,mid+1,r);
}
long long ask(long long p,long long l,long long r){
if(t[p].l>=l&&t[p].r<=r)return t[p].minn;
long long mid=(t[p].l+t[p].r)>>1;
long long minn=1e9;
if(l<=mid)minn=min(minn,ask(p<<1,l,r));
if(r>mid)minn=min(minn,ask(p<<1|1,l,r));
return minn;
}
void change(long long p,long long l,long long val){
if(t[p].l==t[p].r){
t[p].minn=val;
return ;
}
long long mid=(t[p].r+t[p].l)>>1;
if(l<=mid)change(p<<1,l,val);
else change(p<<1|1,l,val);
t[p].minn=min(t[p<<1].minn,t[p<<1|1].minn);
return ;
}
char str[N];
int main(){
cin>>n>>m;
cin>>1+str;
p[0]=1;
for(long long i=1;i<=n;++i){
p[i]=p[i-1]*P;g[i]=g[i-1]*P+str[i]-'a'+1;
}
for(long long i=1;i<=n;++i)scanf("%d",&a[i]);
for(long long i=1;i<=m;++i){
cin>>1+str;
len[i]=strlen(1+str);
for(long long j=1;j<=len[i];++j){
hs[i]=hs[i]*P+str[j]-'a'+1;
}
}
build(1,1,n);f[0]=0;change(1,1,a[1]);
long long now=0,las=0;
for(long long i=1;i<=n;++i){
f[i]=1e9;change(1,i,a[i]+f[i-1]);
now=0;
for(long long j=1;j<=m;++j){
if(i<len[j])continue;
if(g[i]-g[i-len[j]]*p[len[j]]==hs[j]){
now=max(now,i-len[j]+1);
}
}
lim[i]=max(lim[i-1],now);
if(now)f[i]=ask(1,lim[i],i);
if(f[i]==1e9)f[i]=f[i-1];
}
cout<<f[n]<<endl;
return 0;
}