2019icpc香港 E. Erasing Numbers(贪心)

题意:给定一个排列n,每次可以选择相邻的三个数,将最大和最小的数删除

问对于1-n中每个a[i]a[i]可不可能是最后被保留下来的那个数?

首先我们要想明白一件事,当一个数组中大于a[i]和小于a[i]的数量相等时,a[i]一定可以被保留下来

而对于在排列中任意一个数a[i],比他大的数和比他小的数的数量之差等于abs(a[i]-1 - (n-a[i]))

也就是说如果我们可以把多出的这些部分按题目意思消掉,a[i]就是可保留的

我们把大于a[i]的数字记作1,小于a[i]的数字记成0

按题目意思,连续三个1或连续三个0可以消掉两个,使得多出的部分减2

而对于不连续的

假设我们多出的是大于a[i]的数,用1表示

11011可以先变成111进而变成1,贡献相当于111

所以我们可以巧妙的维护一个tmp,遇到想要消掉的数++,不想消掉的数--

满三减二

而对于a[i]本身,是不能被跨越的,所以经过a[i]时tmp要置0

代码如下:

#include <bits/stdc++.h>
#define int long long
#define pb push_back
#define fer(i,a,b) for(int i=a;i<=b;++i)
#define der(i,a,b) for(int i=a;i>=b;--i)
#define all(x) (x).begin(),(x).end()
#define pll pair<int,int>
#define et  cout<<'\n'
#define xx first
#define yy second
using namespace std;
template <typename _Tp>void input(_Tp &x){
    char ch(getchar());bool f(false);while(!isdigit(ch))f|=ch==45,ch=getchar();
    x=ch&15,ch=getchar();while(isdigit(ch))x=x*10+(ch&15),ch=getchar();
    if(f)x=-x;
}
template <typename _Tp,typename... Args>void input(_Tp &t,Args &...args){input(t);input(args...);}
const int N=1e6+10;
int a[N];
int n;
signed main(){
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);
    int T;
    cin>>T;
    while(T--){
        cin>>n;
        fer(i,1,n) cin>>a[i];
        function<bool(int)> check=[](int tar){
            bool fl=a[tar]<(n+1)/2;
            int k=a[tar]-1;
            int k2=n-a[tar];
            k=abs(k-k2);
            int tmp=0;
            fer(i,1,n){
                if(i==tar){
                    tmp=0;
                    continue;
                }
                if((a[i]<a[tar])!=fl){
                    tmp++;
                    if(tmp==3){
                        tmp=1;
                        k-=2;
                    }
                }
                else{
                    tmp=max(tmp-1,0ll);
                }
            }
            return k<=0;
        };
        fer(i,1,n){
            cout<<check(i);
        }
        cout<<endl;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值