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

猜你喜欢

转载自www.cnblogs.com/ckr1225/p/9460767.html