題意:
給一個長度爲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 <iostream>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <queue>
#include <stack>
#include <map>
//
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;
}
};
用{內容}重載運算符‘<‘;
這個寫法因爲右邊是堆頂 (隊列首), 又是大根堆,於是<,然後用{比較內容}重載這個運算符;