【NOIP2021国庆集训Day1】A.撰写博客
【题意】
给定一个长度为n的文章(小写字母),和m个不合法单词,修改文章中每个字母都有$a_i$的代价,问要文章中不存在不合法的单词,最小代价是多少
数据范围:$n\leq2*10^5,m\leq10$
【分析】
首先,我们可以预处理出来每个位置作为结尾,不包含任何不合法单词的最长的区间pos[i](也就是左端点最远的位置)
然后,我们考虑dp
对于位置i,能够由j位置转移而来,当且仅当j+1-i之间没有不合法单词,所以我们要在pos[i]之后转移而来
$f[i]=min_{pos[i]\leq j \le i}{f[j]}+a[i],$
这个式子可以用单调队列来优化转移
这样时间复杂度为$O(nm+\sum{|len|})$
【代码】
#include<bits/stdc++.h> using namespace std; #define re register #define int long long inline int read() { int f=1,lzx=0;char c=getchar(); while(c>'9'||c<'0'){if(c=='-')f=-f;c=getchar();} while(c<='9'&&c>='0'){lzx=lzx*10+c-'0';c=getchar();} return lzx*f; } const int N=2e5+10,p=1e6+3; char s[N],t[12][N]; int mod[2]={1e9+7,1e9+9},a[N],len[12],q[N],h,T,f[N], hash1[N][2],hasht[12][2],power[N][2],fir[N]; inline int calc(int x,int l,int id) { int y=x+l-1,res=hash1[y][id]; res-=hash1[x-1][id]*power[y-x+1][id]%mod[id]; return (res+mod[id])%mod[id]; } inline int check(int x,int y) { return calc(x,len[y],0)==hasht[y][0]&&calc(x,len[y],1)==hasht[y][1]; } inline int fit(int x) { if(fir[x]==x)return fir[x-1]; return fir[x]; } signed main() { freopen("wzadx.in","r",stdin); freopen("wzadx.out","w",stdout); int n=read(),m=read(),ans=0; scanf("%s",s+1); for(re int i=1;i<=n;i++) a[i]=read(),ans+=a[i]; for(re int i=1;i<=m;i++) { scanf("%s",t[i]+1); len[i]=strlen(t[i]+1); } power[0][0]=power[0][1]=1; for(re int i=1;i<=n;i++) for(re int j=0;j<2;j++) power[i][j]=power[i-1][j]*p%mod[j]; for(re int i=1;i<=n;i++) for(re int j=0;j<2;j++) hash1[i][j]=(hash1[i-1][j]*p+s[i]-'a')%mod[j]; for(re int i=1;i<=m;i++) { int tmp[2];tmp[0]=tmp[1]=0; for(re int j=1;j<=len[i];j++) for(re int k=0;k<2;k++) tmp[k]=(tmp[k]*p+t[i][j]-'a')%mod[k]; hasht[i][1]=tmp[1]; hasht[i][0]=tmp[0]; } for(re int i=1;i<=n;i++) for(re int j=1;j<=m;j++) { if(i+len[j]-1>n+1)continue; if(check(i,j)) fir[i+len[j]-1]=max(fir[i+len[j]-1],i); } for(re int i=1;i<=n+1;i++) fir[i]=max(fir[i],fir[i-1]); q[++h]=0; for(re int i=1;i<=n+1;i++) { while(T<h&&q[T+1]<fir[i-1])T++; f[i]=f[q[T+1]]+a[i]; while(T<h&&f[q[h]]>=f[i])h--; q[++h]=i; } cout<<f[n+1]<<endl; return 0; }