题目大意:
给你n个数,对于每个长度len (1<=len<=n)中的最小值所组成的集合是不是一个(n-i+1)的全排列,是用1表示,不是用0表示
题目思路:
1.用单调栈求出当前a[i]能控制的范围l[i],r[i] --单调栈求区间最值
2.如果对于长度len的集合中数字 num 是第一次出现,那么利用树状数组对 tree[num]++
这样就check一下 query(n-i+1)是不是大于等于n-i+1就能知道当前长度len符不符合条件
具体操作:
遍历ans[i]时候一定要倒着
拿这组样例 1 3 3 2 来说
因为我们求的是能控制的左右区间的最大范围
如果上来就去找len[1]的话是谁也找不到的,但是len=1又是符合条件的
但如果倒着遍历
先找Len=3 , num = 1 .tree[1]++ ,check — ok
len=2 , num =2 ,3 .tree[2]++,tree[3]++ ,check—ok
len =1 无 check —ok
Code:
int l[maxn],r[maxn],a[maxn],n,ans[maxn],vis[maxn],b[maxn];
int t[maxn];
vector<int>len[maxn];
int lowbit(int x) {
return x&(-x);
}
void add(int x) {
while(x<=n) t[x]++,x+=lowbit(x);
}
int q(int x) {
int ans=0;
while(x>0) {
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
int main() {
int _ = read();
while(_--) {
mst(vis,0);
n=read();
rep(i,1,n) a[i] = read(), ans[i]= t[i] =l[i] = r[i] = 0,len[i].clear();
stack<int>st;
for(int i=1 ; i<=n ; i++) {
while(st.size()&&a[i]<=a[st.top()])st.pop();
if(st.size()==0) l[i] = 1;
else l[i] = st.top()+1;
st.push(i);
}
while(st.size()) st.pop();
for(int i= n ; i>=1 ; i--) {
while(st.size()&&a[i]<=a[st.top()]) st.pop();
if(st.size()==0) r[i] = n;
else r[i] = st.top()-1;
st.push(i);
}
while(st.size()) st.pop();
rep(i,1,n) len[r[i]-l[i]+1].push_back(a[i]);
for(int i=n ; i>=1 ; i--) {
for(int num:len[i]) {
vis[num]++;
if(vis[num]==1) add(num);
}
int sum = q(n-i+1);
if(sum>=n-i+1) ans[i] =1;
}
rep(i,1,n) cout<<ans[i];
cout<<endl;
}
return 0;
}