codeforces750E
线段树简单题
对于线段树每个区间维护一个矩阵a[i][j]表示仅用这个区间内的数,从状态i得到状态j并且合法至少要删除几个
0对应没有,1对应“2”,2对应“20”,3对应“201”,4对应“2017”
合并矩阵a[i][j]=min(a[i][j],a[i][k]+a[k][j])
代码如下:
#include<bits/stdc++.h> #define inf 1000000000 #define N 1000005 using namespace std; char s[N];int n,Q,l,r; struct mat{int a[5][5];}d[N]; mat operator + (mat aa,mat bb){ mat cc; for (int i=0;i<5;i++) for (int j=0;j<5;j++) cc.a[i][j]=inf; for (int i=0;i<5;i++) for (int j=0;j<5;j++) for (int k=0;k<5;k++) cc.a[i][j]=min(cc.a[i][j],aa.a[i][k]+bb.a[k][j]); return cc; } void build(int k,int l,int r){ if (l==r){ int c=s[l]-'0'; for (int i=0;i<5;i++){ for (int j=0;j<5;j++){ if (i==j) d[k].a[i][i]=0; else d[k].a[i][j]=inf; } } if (c==2) d[k].a[0][1]=0,d[k].a[0][0]=1; if (c==0) d[k].a[1][2]=0,d[k].a[1][1]=1;//相当于原来状态不变,删除c这个东西 if (c==1) d[k].a[2][3]=0,d[k].a[2][2]=1; if (c==7) d[k].a[3][4]=0,d[k].a[3][3]=1; if (c==6) d[k].a[3][3]=1,d[k].a[4][4]=1;//加入了6,如果之前是3即201要删c,如果是4,即2017也要删c return; } int mid=(l+r)>>1; build(k*2,l,mid);build(k*2+1,mid+1,r); d[k]=d[k*2]+d[k*2+1]; } mat query(int k,int l,int r,int x,int y){ if (x<=l&&y>=r) return d[k]; int mid=(l+r)>>1; if (y<=mid) return query(k*2,l,mid,x,y); else if (x>mid) return query(k*2+1,mid+1,r,x,y); else return query(k*2,l,mid,x,mid)+query(k*2+1,mid+1,r,mid+1,y); } int main(){ scanf("%d%d",&n,&Q); scanf("%s",s+1); build(1,1,n); while (Q--){ scanf("%d%d",&l,&r); int tmp=query(1,1,n,l,r).a[0][4]; if (tmp==inf) puts("-1"); else printf("%d\n",tmp); } return 0; }