Codeforces 1353D


题面

Prob




题意

一个长度为 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;
}

原文地址:https://www.cnblogs.com/stelayuri/p/12892451.html