Problem F - Football Free Kick(数组1e9的插入和删除)

原题: https://cn.vjudge.net/problem/Gym-101864F

题意:

开始1到k为1,k+1到n为0,每次操作移动一个1到一个0的位置,保证操作合法。求每次操作后1到n有几个连续的0区间(100010有两个)

解析:

因为1e9的原因所以不能开数组。

考虑插入的情况:既然合法,也就是说当前位置之前为0,而且只会插在两个连续1区间的中间,所以对于连续1区间,我们不需要对整个区间的每个位置打标记,只需要对左端点和右端点打标记。那么在插入的时候,只需要判断当前空左边有没有打标记,右边有没有打标记即可。(两边有则空–,两边无则空++)

再考虑移走的情况,因为本就是01和10的关系,所以所有的操作都可以共享,即:对于一个连续0区间的左右端打标记,之后操作完全相同

#include<bits/stdc++.h>
using namespace std;


map<int,bool>non,vis;

int insert(int p){

    int add=0;
    int l=0,r=0;
    if(vis[p+1])r++;
    if(vis[p-1])l++;
    if(l+r==2)add--;
    else if(l+r==1);
    else add++;

    vis[p]=1;
    if(l==1&&r==0){
        non[p]=0;
        non[p+1]=1;
    }
    else if(l==0&&r==1){
        non[p]=0;
        non[p-1]=1;
    }
    else if(l&&r){
        non[p]=0;
    }
    else{
        non[p]=0;
        non[p+1]=non[p-1]=1;
    }

    return add;
}

int erase(int p){

    int add=0;
    int l=0,r=0;//左边没有
    if(non[p+1])r++;
    if(non[p-1])l++;
    if(l+r==2)add--;
    else if(l+r==1);
    else add++;

    non[p]=1;

    if(l==1&&r==0){
        vis[p]=0;
        vis[p+1]=1;
    }
    else if(l==0&&r==1){
        vis[p]=0;
        vis[p-1]=1;
    }
    else if(l&&r){
        vis[p]=0;
    }
    else{
        vis[p]=0;
        vis[p+1]=vis[p-1]=1;
    }

    return add;
}

int main(){
    int t;scanf("%d",&t);int ca=0;
    while(t--){
        printf("Case %d:\n",++ca);
        non.clear();vis.clear();
        int n,k,q;
        scanf("%d%d%d",&n,&k,&q);
        vis[0]=vis[n+1]=vis[1]=vis[k]=1;
        if(k<n)non[k+1]=non[n]=1;
        int now=1;
        while(q--){
            int x,y;
            scanf("%d%d",&x,&y);
            if(x!=y)
                now+=insert(y),
                now+=erase(x);
            printf("%d\n",now);
        }
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/82956923