UOJ278 【UTR #2】题目排列顺序 题解
题目链接:#278. 【UTR #2】题目排列顺序
题意:
“又要出题了。” 宇宙出题中心主任 —— cxy ,坐在办公桌前策划即将到来的 UOI。
这场比赛有 $n$ 道题, cxy 需要决定这些题目的难度,然后再在汪洋大海中寻找符合该难度的题目。
题目的难度可以用一个 $1$ 到 $n$ 的排列 $a_1, \dots, a_n$ 表示,其中 $a_i$ 表示第 $i$ 道题目在这 $n$ 道题目中是第 $a_i$ 简单的题目,即恰有 $a_i - 1$ 道题目比第 $i$ 道题目简单。
经验丰富的 cxy 早就悟出了一种科学地决定难度顺序的方法。首先, cxy 定义了难度递增子序列为序列 $a_{p_1}, a_{p_2}, \dots, a_{p_k}$ ($1 \le p_1 < p_2 < \dots < p_k \le n$) 满足 $a_{p_1} < a_{p_2} < \dots < a_{p_k}$ 。然后, cxy 决定了 $n$ 个整数 $f_1, \dots, f_n$,他希望找出一个难度顺序使得对于每个 $1 \le i \le n$ 均满足以 $a_i$ 结尾的难度递增子序列的最长长度恰好为 $f_i$。
但 cxy 日理万机,于是他找到了你,请你帮助 cxy 构造一个符合条件的 $a_1, \dots, a_n$ 吧!
输入格式:
第一行一个正整数 $n$。
接下来一行 $n$ 个数,其中第 $i$ 个数表示 $f_i$。($1 \le f_i \le n$)
输出格式:
输出一行 $n$ 个数,表示 $a_1, \dots, a_n$。
题目保证至少存在一组解。如有多组解,输出任意一组均可。
数据范围:
$1 \le n \le 10^5$
若题目有解,则 $f_1 = 1$ ,且若 $f_i = k (k>1)$ ,则必存在 $1 \le j < i$ 使得 $f_j = k-1$ 。
因此构造序列使得 $f_i < f_j$ 时必有 $a_i < a_j$ ;当 $f_i = f_j$ 时,必有 $a_i > a_j$。( $i < j$ )
前者是显然的,后者解释一下。当 $f_i=f_j$ 时 $a_i$ 若小于 $a_j$ ,则 $f_j$ 应当为 $k+1$ 。因此这么构造是合法的。
具体地,把 $(f_i,a_i)$ 看作一个 pair<int,int>
,我们可以用计数排序来做,注意要正序做。
时间复杂度 $\mathcal{O}(n)$
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
void up(int &x,int y) { x < y ? x = y : 0; }
void down(int &x,int y) { x > y ? x = y : 0; }
#define N ((int)(1e5+15))
int n,m,a[N],b[N],buf[N];
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
// freopen("check.in","r",stdin);
// freopen("check.out","w",stdout);
cin >> n;
for(int i=1; i<=n; i++) { cin >> a[i]; ++buf[a[i]]; up(m, a[i]); }
for(int i=1; i<=m; i++) buf[i] += buf[i-1];
for(int i=1; i<=n; i++) cout << (buf[a[i]]--) << " \n"[i==n];
return 0;
}
参考文献: