https://codeforces.com/contest/1353/problem/D
题意:给定一个长度为n的全0数组aa,每次进行以下操作直到所有元素均不为零:在第ii次操作中,取最长的全为0的一段子序列(优先取最左边的),令a[len2/2]=i。其中len为偶数,取l+rl+r或l+r−1。
思路:首先题目中要求每次分区间时优先考虑长度最大且最左边的区间优先,因此比较容易想到用优先队列,这里我们将pair键值对放入优先队列中,第一个关键字存长度,第二个关键字存左端点,通过这两个关键词可以将右端点r算出来,在放进队列时要判断边界条件,要注意的是重写优先队列的优先级时是跟实际比较大小相反的,就像在优先队列中greater<int>是小的优先一样的道理。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
struct cmp{
bool operator()(pair<int,int> a,pair<int,int> b){
if(a.first==b.first) return a.second>b.second;
return a.first<b.first;
}
};
int a[200005];
int main()
{
priority_queue<pair<int,int>,vector<pair<int,int> >,cmp > q;
int t,n;
cin>>t;
while(t--){
cin>>n;
q.push(make_pair(n,1));
ll c=1;
while(!q.empty()){
int r=q.top().first; //长度
int l=q.top().second;
int x=l+r-1; //实际的r
q.pop();
int mid=(2*l+r-1)/2;
a[mid]=c;
if(mid-1>=l) q.push(make_pair(mid-l,l));
if(mid+1<=x) q.push(make_pair(x-mid,mid+1));
c++;
}
for(int i=1;i<=n;i++) cout<<a[i]<<" ";
cout<<endl;
}
return 0;
}