UOJ#10 【UTR #1】pyx的难题

问题描述

pyx喜欢出题给cyb做。为了增加难度,他有可能在cyb还没做完前面的题的时候就把新题目出给他。

假设pyx总共要给cyb出n道题,其中第i道题是在ti时刻出给cyb的,cyb需要花si秒才能AC此题。

pyx比较高产,出题时刻可能相同(也就是pyx可能同一时刻丢出了动态仙人掌和可持久化带插入仙人掌路径k大值给cyb)。

按照cyb的个人喜好,他给n道题目标上了互不相同的优先级pi。

cyb做题过程是这样的:

    cyb收到题目是瞬间的事情。
    每次,cyb先收到所有pyx新出的题。
    接着,cyb把现在所有待解决的题目按照优先级瞬间排序。(当然优先级是互不相同的)
    然后,cyb会花恰好1秒钟时间在那个优先级最高的题,然后解决该题需要花的时间减少1秒。如此循环。
    由于是神犇之间的交流,十分有记录的意义,需要载入史册,这个光荣的任务就交给修电脑的oier们了。

现在给你n道题的ti,si,pi。然而不幸的是,由于奇怪的原因,你一不小心把某一道题的优先级弄丢了。

你为了掩饰自己的错误,通过不断打听,得知了cyb在时刻T时AC了这道优先级未知的题目。(即第T秒末,第T秒结束的时刻)

你想试着推测出优先级,然而很显然,方案可能不止一种。你决定编造这个题目的优先级,使得cyb仍会在时刻T AC此题。

除此之外,你还要帮cyb算出所有题目被解决的时刻,以展示你是多么的负责。

也就是说,你要求出一个可行的优先级,并求出在这个优先级下,所有题目被解决掉的时刻。

输入格式

第一行输入一个正整数n。

接下来n行描述一个题目,第i行有三个整数分别是ti,si,pi,含义如前所述。有且仅有一个题目(我们不妨称其为题目x)的px=−1,表示该题的优先级未知。

最后一行包含一个整数T——任务x完成的时刻。

所有题目的优先级互不相同,但 ti 并不一定互不相同。

输出格式

在第一行输出一个正整数px——即题目x的优先级(请记住所有题目的优先级必须互不相同)。接下来输出n个数字,第i个数字表示第i个题目结束时的时间。

我们保证数据有解。如果有多解,输出任意一组解即可。

输出的优先级必须在[1,109+1]之内。

AC通道 UOJ#10【UTR #1】pyx的难题

所以说 上课记笔记什么的 还是要专心 不然下来就让你写个程序逆推老师讲的啥

题解

先要排序对吧

由于做题是按照等级制度来的 等级越高 做题的优先级就越高
从左到右遍历就无法快速地确定当前做题的优先级
所以说 我们按照等级从高到底来加入题目

这样子做的好处在于
我们做的每一道题目都是当前它所在的时间段中 优先级最高的
除非这段时间已经被其它题目占用了 否则 这段时间就归这道题了

说人话就是

一道题的发布时间为si 做它要li
我们可以通过这道题目插入时间就可以知道 做它的时间段是从si开始的
如果在si到si+li之间 有时间被其它题目占用的话 
    那么就一定是优先级高于它的 那我们果断跳过
否则 我们就可以占用
    因为后面加入的题目优先级一定低于它

骚操作 离散化

因为时间范围太大 所以我们不可能枚举每一秒

因此 我们按照题目的得到时间把所有时间进行分段
并且记录每一个时间段的开始时间和已经用到哪里了
同时 我们可以知道当前时间段的结束时间段就是下一个时间段的开始时间

比如 start[5]=10 used[5]=15 start[6]=20
第五个时间段从10开始
目前 10-14已经被占用了 下一个可用的时间点是15
而且第五个时间段的结束点在20

然后每做一道题目 我们就对它所占用的时间段进行更新

常规操作 并查集

对于每一个时间段 由于它是按照得到题目的时间进行分割的
所以说 有极大的可能 一个时间段做不完一道题
这个时候 我们就要占用后面的时间段了

假如一个时间段 i 被我们用完了
就应该更新 used[i]=start[i+1]
这样子 当前时间段的可用时间就是 start[i+1]-used[i]=0

但是我们如果一个时间段一个时间段地跑 就会极大地占用时间

于是 我们需要一个快速跳过已用区间的工具 并查集

假设i的时间段被完全占用
fa[i]=i+1
然后在每一次对时间段i操作之前 我们先进行跳过操作
即 先同并查集 查到没有被完全被占用的时间段

最后是回答第一个问题

没做的题目的优先级

对于位置题目的时间段 s-e
它一定是被塞满了的

因为如果没有更高级的题目占用时间的话 就一定会做它
不会有时间空着

所以我们就每加入一道题目就对s-e的时间进行更新

当s-e的空时间的等于做这道题目的时间时 优先级就是上一道的优先级-1
当然 假如已经有题目的优先级==上一道的优先级-1 就要往下面继续加题

注意

数据范围 要用long long

附上很弱的对拍代码

#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;

struct ques{int s,l,lev,id;}data[300123];
bool cp(ques a,ques b){return a.lev>b.lev;}

int posn,fa[300123];
long long st,en,used=0;
long long star[300123],pos[300123],etime[300123];

int find(int p)
{
    if(fa[p]!=p)fa[p]=find(fa[p]);
    return fa[p];
}

long long work(int p,long long l)
{
    int np=lower_bound(pos+1,pos+posn+1,p)-pos,al;
    while(1)
    {
        np=find(np);
        if(pos[np+1]+l<=star[np])
        {
            if(pos[np]>=st&&pos[np]<=en)used+=l;
            star[np]+=l;return star[np];
        }
        else
        {
            al=pos[np+1]-star[np];
            if(pos[np]>=st&&pos[np]<=en)used+=al;
            l-=al;star[np]=pos[np+1];fa[np]=np+1;
        }
    }
}

int main()
{
//  freopen("pyx.in","r",stdin);
//  freopen("pyx.out","w",stdout);
    int N,ns,nl,nlev,sid,len,le,n=0,last=1e9+2;
    scanf("%d",&N);
    for(int i=1;i<=N;i++)
    {
        scanf("%d%d%d",&ns,&nl,&nlev);
        pos[i]=ns;
        if(nlev==-1)sid=i,st=ns,len=nl;
        else data[++n].id=i,data[n].s=ns,data[n].l=nl,data[n].lev=nlev;
    }
    scanf("%d",&en);le=en-st;
    sort(data+1,data+N,cp);
    sort(pos+1,pos+N+1);
    posn=unique(pos+1,pos+N+1)-pos;
    for(int i=1;i<=posn;i++)star[i]=pos[i],fa[i]=i;pos[posn]=1e9+2;

    int np;
    for(np=1;np<=n;np++)
    {
        if(len+used==le&&data[np].lev+1<last)
        {
            printf("%d\n",data[np].lev+1);
            etime[sid]=work(st,len);break;
        }
        else etime[data[np].id]=work(data[np].s,data[np].l),last=data[np].lev;
    }
    if(!etime[sid])printf("%d\n",last-1),etime[sid]=work(st,len);
    for(;np<=n;np++)etime[data[np].id]=work(data[np].s,data[np].l);
    for(int i=1;i<=N;i++)printf("%lld ",etime[i]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值