UOJ278 题目排列顺序

6 篇文章 0 订阅
吉米多出题斯基面临UOI比赛的出题任务,需要确定题目的难度顺序。他定义难度递增子序列,并希望每个题目结束的子序列长度等于特定值f[i]。你需要帮助他构造满足条件的难度排列。问题转化为建立约束条件并进行拓扑排序。题目保证有解,输出任意满足条件的一组即可。
摘要由CSDN通过智能技术生成

“又要出题了。” 宇宙出题中心主任 —— 吉米多出题斯基,坐在办公桌前策划即将到来的 UOI。

这场比赛有 nn 道题,吉米多出题斯基需要决定这些题目的难度,然后再在汪洋大海中寻找符合该难度的题目。

题目的难度可以用一个 11 到 nn 的排列 a1,…,ana1,…,an 表示,其中 aiai 表示第 ii 道题目在这 nn
道题目中是第 aiai 简单的题目,即恰有 ai−1ai−1 道题目比第 ii 道题目简单。

经验丰富的吉米多出题斯基早就悟出了一种科学地决定难度顺序的方法。首先,吉米多出题斯基定义了难度递增子序列为序列
ap1,ap2,…,apkap1,ap2,…,apk (1≤p1< p2<⋯< pk≤n1≤p1< p2< ⋯< pk≤n) 满足
ap1< ap2<⋯< apkap1< ap2< ⋯< apk 。然后,吉米多出题斯基决定了 nn 个整数
f1,…,fnf1,…,fn,他希望找出一个难度顺序使得对于每个 1≤i≤n1≤i≤n 均满足以 aiai
结尾的难度递增子序列的最长长度恰好为 fifi。

但吉米多出题斯基日理万机,于是他找到了你 —— 风璃殇做不出题耶维奇,请你帮助吉米多出题斯基构造一个符合条件的 a1,…,ana1,…,an
吧! 输入

第一行一个正整数 nn。

接下来一行 nn 个数,其中第 ii 个数表示 fifi。(1≤fi≤ n1≤fi≤n) 输出

输出一行 nn 个数,表示 a1,…,ana1,…,an。

题目保证至少存在一组解。如有多组解,输出任意一组均可。

对于某一个位置 i 的答案f[i]应该满足:1.可以达到这个答案。2.答案不能变的更优。
对于1,应该让当前数大于最小的 f[i1] 对应的数【可以看出,就是最右端的那个】。对于2,应该让当前数小于最小的 f[i] 对应的数【也是最靠右的】。
所以扫描一遍维护每个 f <script type="math/tex" id="MathJax-Element-210">f</script>值最靠右的位置建立约束条件,拓扑一遍。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a[100010],f[100010],fir[100010],ne[1000010],to[1000010],du[100010],right[100010],que[100010],n,tot;
void add(int u,int v)
{
    ne[++tot]=fir[u];
    fir[u]=tot;
    to[tot]=v;
    du[v]++;
}
int main()
{
    int i,j,u,v,hd,tl;
    scanf("%d",&n);
    for (i=1;i<=n;i++)
      scanf("%d",&f[i]);
    for (i=1;i<=n;i++)
    {
        if (f[i]>1) add(i,right[f[i]-1]);
        if (right[f[i]]) add(right[f[i]],i);
        right[f[i]]=i;
    }
    hd=1;
    tl=0;
    for (i=1;i<=n;i++)
      if (!du[i])
        que[++tl]=i;
    for (i=n;i;i--)
    {
        u=que[hd++];
        a[u]=i;
        for (j=fir[u];j;j=ne[j])
          if (--du[v=to[j]]==0)
            que[++tl]=v;
    }
    for (i=1;i<=n;i++)
      printf("%d%c",a[i],i==n?'\n':' ');
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值