题目链接
给一个长度为n的空序列,然后往里面填1-n的数字;
int cnt=1;
找序列中最长(如果多个最长则取最左边的序列)的连续全空区间:并且赋值cnt++;循环这个操作n次:
eg:
Consider the array a of length 5 (initially a=[0,0,0,0,0]). Then it changes as follows:
Firstly, we choose the segment [1;5] and assign a[3]:=1, so a becomes [0,0,1,0,0];
then we choose the segment [1;2] and assign a[1]:=2, so a becomes [2,0,1,0,0];
then we choose the segment [4;5] and assign a[4]:=3, so a becomes [2,0,1,3,0];
then we choose the segment [2;2] and assign a[2]:=4, so a becomes [2,4,1,3,0];
and at last we choose the segment [5;5] and assign a[5]:=5, so a becomes [2,4,1,3,5].
一开始做法是开两个queue,算是一个贪心做法,但是发现难以处理不同批次的同长度区间;于是想到了优先队列写法
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
//
using namespace std;
const int INF = 0x3f3f3f3f;//1.06e9大小
const int mod1 = 1e9 + 7;
const int mod2 = 998244353;
const int mod3 = 1e9;
const double PI = 3.14159265;
const double eps =1e-10;
typedef unsigned long long ULL;
typedef long long LL;
#define debug printf("**debug**\n")
#define ms(x, n) memset(x,n,sizeof(x))
/*
*/
struct node
{
int l,r;
int w;
bool operator < (const node a) const
{
if(w==a.w)
return l>a.l;
return w<a.w;
}
};
int a[200001];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
priority_queue<node>q;
q.push({1,n,n-1+1});
int cnt=1;
while(!q.empty())
{
auto t=q.top();
q.pop();
int l=t.l,r=t.r;
if((r-l+1)%2)
{
a[(l+r)/2]=cnt++;
if(l<(l+r)/2)q.push({l,(l+r)/2-1,((l+r)/2-l)});
if(r>(l+r)/2)q.push({(l+r)/2+1,r,(r-(l+r)/2)});
}
else
{
a[(l+r-1)/2]=cnt++;
if(l<(l+r-1)/2)q.push({l,(l+r-1)/2-1,((l+r-1)/2-l)});
if(r>(l+r-1)/2)q.push({(l+r-1)/2+1,r,r-(l+r-1)/2});
}
}
for(int i=1;i<=n;i++)
{
printf("%d ",a[i]);
}
printf("\n");
}
return 0;
}
对于优先队列维护结构体的数值的时候,我们写法也会像sort(from,to,cmp)的cmp重载一样:
struct node
{
int l,r;
int w;
bool operator < (const node a) const
{
if(w==a.w)
return l>a.l;
return w<a.w;
}
};
用{内容}重载运算符‘<‘;
这个写法因为右边是堆顶 (队列首), 又是大根堆,于是<,然后用{比较内容}重载这个运算符;