1. 程式人生 > 其它 >【NOIP2021國慶集訓Day1】A.撰寫部落格

【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; }