题面
题意
一个长度为 n 的数组,初始值全部为 0
每次选择其中最长的一段全0连续子数组,如果多个并列最长,取最左边的那个,并标记其左右区间 L R
如果这个子数组包含的元素个数为奇数(R-L+1为奇数),则将这一段区间最中间那个位置标记上数字
如果这个子数组包含的元素个数为偶数,则将这一段区间内中间靠左的那个位置标记上数字
数字依次标记 1~n,最后输出这个数组
解题思路
可以采用搜索的方法
建立结构体后,用优先队列来把个数最多的、个数相同区间靠左的放在队列的前端
每次取队列前端的元素出队列处理即可(类似线段树建树)
注意使用优先队列时需要重载大于运算符
完整程序
#include<bits/stdc++.h>
using namespace std;
struct node
{
int siz,l,r;
bool operator > (const node& a) const //优先队列重载大于运算符
{
if(siz!=a.siz)
return siz<a.siz; //将区间包含的元素较多的放在前面
return l>a.l; //相同个数则将left小的放在前面
}
};
int ar[200050];
void solve()
{
int n,tmp=1,mid,l,r;
cin>>n;
priority_queue<node,vector<node>,greater<node> > q;
q.push(node{n,1,n});
while(!q.empty())
{
node nd=q.top();
q.pop();
l=nd.l;
r=nd.r;
if(l==r) //如果区间只包含一个元素,直接赋值即可
ar[l]=tmp++;
else
{
if((r-l)&1)
mid=(r+l-1)>>1;
else
mid=(r+l)>>1;
ar[mid]=tmp++; //给题意描述的位置赋值
//接下来相当于讨论[l,r]区间去掉mid后形成的两个区间
if(l<mid) //如果[l,mid-1]区间存在
q.push(node{mid-l,l,mid-1});
if(r>mid) //如果[mid+1,r]区间存在
q.push(node{r-mid,mid+1,r});
}
}
for(int i=1;i<=n;i++)
cout<<ar[i]<<' ';
cout<<'
';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T;cin>>T;
for(int t=1;t<=T;t++)
solve();
return 0;
}