E:题目链接:https://codeforces.com/gym/102452/problem/E
题目大意:给定一个序列,任选三个连续的数去掉一个最小的和最大的,问最后哪些数可能留下来。
题目思路:因为n是5000以内的数,想到n^2算法,枚举每一位数,比它大的数设为1,比它小的数设为0。首先,因为n是奇数,很容易想到1和0的个数是都是奇数或者都是偶数,也就是他们之间相差2k,其中k=(n-a[i]-a[i]+1)/2。
其次,假设x想要剩余下来,最后的情况必定是01x,10x,x01,x10,1x0,0x1,这6种情况。这些情况的共同点就是01的个数相同,也就是说,我们只要删除多的个数,使得两者相同,下面以0举例(1是同理的)。如果出现000,则可变为一个0,如果出现01或者10,无论这个左右出现0或1,这个01或10都可取消。0和1的差值不变,0的个数减一。于是我们只要找到000的个数,删除一次0和1的差值减少2,若1比0多,则0的个数则会便为0.
综上,只要删除连续三个的个数大于等于k,即可最后留下。
#include<bits/stdc++.h>
using namespace std;
const int maxn=5e3+9;
int a[maxn],ans[maxn];
int solve(int n,int pos,int s,int e,bool flag){
//flag 1:需要删除0的个数,0:需要删除1的个数
//now 当前需要删除的个数剩余的,ret 已经删除的次数。
int now=0,ret=0;
for(int i=s;i<=e;i++){
if(flag){
if(a[pos]>a[i]){
if(++now==3){
now=1,ret++;
}
}else if(--now==-1) now=0;
}else{
if(a[pos]<a[i]){
if(++now==3){
now=1,ret++;
}
}else if(--now==-1) now=0;
}
}
return ret;
}
int main(){
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++){
bool flag=true;
ans[i]=0;
if(a[i]==(n+1)/2){
ans[i]=1;
continue;
}else if(a[i]<(n+1)/2) flag=false;
int m=solve(n,i,1,i-1,flag)+solve(n,i,i+1,n,flag);
int ne=abs((n+1)/2-a[i]);
if(m>=ne) ans[i]=1;
else ans[i]=0;
}
for(int i=1;i<=n;i++) printf("%d",ans[i]);
printf("\n");
}
return 0;
}