传送门
这是一道CF原题,思路在这
线段树维护的时候,只要从右到左维护,不就变成了只能有2019不能有2018了吗,(关键是我也不会正着考虑呀T T
#include<bits/stdc++.h>
#define il inline
#define pb push_back
#define ms(_data,v) memset(_data,v,sizeof(_data))
#define SZ(a) int((a).size())
using namespace std;
typedef long long ll;
const ll inf=0x3f3f3f3f;
const int N=2e5+5;
//il int Add(ll &rt,ll y) {return rt=rt+y>=mod?rt+y-mod:rt+y;}
//il int Mul(ll &rt,ll y) {return rt=rt*y>=mod?rt*y%mod:rt*y;}
char s[N];
int num[N];
struct Ma {
int mat[5][5];
Ma operator + (const Ma x) const{
Ma ans;
ms(ans.mat,0x3f);
for(int i=0; i<5; ++i) {
for(int j=0; j<5; ++j) {
for(int k=0; k<5; ++k) {
ans.mat[i][j]=min(ans.mat[i][j],mat[i][k]+x.mat[k][j]);
}
}
}
return ans;
}
} a[N<<2];
/*
状态0:连2都没有
状态1:只有2,没有0连在后面
状态2:出现20,没有1连在后面
状态3:出现201,没有9连在后面
状态4:出现2019
*/
il void build(int l,int r,int rt) {
if(l==r) {
for(int i=0; i<5; ++i)
for(int j=0; j<5; ++j) a[rt].mat[i][j]=(i==j)?0:inf;
if(num[l]==2) a[rt].mat[0][1]=0,a[rt].mat[0][0]=1;
if(num[l]==0) a[rt].mat[1][2]=0,a[rt].mat[1][1]=1;
if(num[l]==1) a[rt].mat[2][3]=0,a[rt].mat[2][2]=1;
if(num[l]==9) a[rt].mat[3][4]=0,a[rt].mat[3][3]=1;
if(num[l]==8) a[rt].mat[3][3]=1,a[rt].mat[4][4]=1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,rt<<1);
build(mid+1,r,rt<<1|1);
a[rt]=a[rt<<1|1]+a[rt<<1];
}
il Ma query(int l,int r,int L,int R,int rt) {
if(L<=l&&r<=R) return a[rt];
int mid=(l+r)>>1;
if(mid<L) return query(mid+1,r,L,R,rt<<1|1);
if(mid>=R) return query(l,mid,L,R,rt<<1);
return query(mid+1,r,L,R,rt<<1|1)+query(l,mid,L,R,rt<<1);
}
int main() {
int n,q;
scanf("%d%d%s",&n,&q,s+1);
for(int i=1;i<=n;++i) num[i]=s[i]-'0';
build(1,n,1);
while(q--) {
int l,r;
scanf("%d%d",&l,&r);
int ans=query(1,n,l,r,1).mat[0][4];
printf("%d\n",(ans==inf?-1:ans));
}
return 0;
}