New Year and Old Subsequence
题意:给定一个长度为 n 的字符串(由阿拉伯数字组成)。m 次询问某段区间至少删除多少个数字能使得该区间包含 “2017” ,并且不包含 “2016” 。
sol:线段树+dp
考虑线段树的合并。对于当前区间我们假想它有邻近的前一个区间,定义dp[i][j] :前一个区间匹配到了 “2017” 的第 i 位,当前区间匹配了 “2017” 的第 j 位(值得注意的是:此匹配为尽可能的匹配,即 j+1 位无法匹配到)最少需要删除多少个数。
#include<bits/stdc++.h> #define ll long long #define ls u<<1 #define rs u<<1|1 #define mm(x) memset(x,0,sizeof(x)) #define debug(x) cout << #x << ":" << x << '\n' using namespace std; int read() { int a=0;int f=0;char p=getchar(); while(!isdigit(p)){f|=p=='-';p=getchar();} while(isdigit(p)){a=(a<<3)+(a<<1)+(p^48);p=getchar();} return f?-a:a; } const int INF=998244353; int n,m; char s[1000050]; struct node { int c[5][5]; void init() { for(int i=0;i<5;++i) for(int j=0;j<5;++j) c[i][j]=INF; for(int i=0;i<5;++i) c[i][i]=0; } void merge(node a,node b) { for(int i=0;i<5;++i) for(int j=0;j<5;++j) { c[i][j]=INF; for(int k=i;k<=j;++k) c[i][j]=min(c[i][j],a.c[i][k]+b.c[k][j]); } } }val[1000050],ans; void build(int u,int l,int r) { if(l==r) { val[u].init(); if(s[l]=='2') val[u].c[0][1]=0,val[u].c[0][0]=1; if(s[l]=='0') val[u].c[1][2]=0,val[u].c[1][1]=1; if(s[l]=='1') val[u].c[2][3]=0,val[u].c[2][2]=1; if(s[l]=='7') val[u].c[3][4]=0,val[u].c[3][3]=1; if(s[l]=='6') val[u].c[3][3]=1,val[u].c[4][4]=1; return ; } int mid=(l+r)>>1; build(ls,l,mid); build(rs,mid+1,r); val[u].merge(val[ls],val[rs]); } void query(int u,int l,int r,int L,int R) { if(L<=l&&r<=R) { if(L==l) ans=val[u]; else ans.merge(ans,val[u]); return ; } int mid=(l+r)>>1; if(L<=mid) query(ls,l,mid,L,R); if(R>mid) query(rs,mid+1,r,L,R); } int main() { n=read(); m=read(); scanf("%s",s+1); build(1,1,n); while(m--) { int l=read(); int r=read(); query(1,1,n,l,r); printf("%d\n",ans.c[0][4]<=n? ans.c[0][4]:-1); } return 0; }

浙公网安备 33010602011771号