【NOI2006】 生日快乐

题目描述
生日快乐
【任务描述】
今天是栋栋的生日,他邀请了 N 个好友参加 Party。朋友们都知道,栋栋最
喜欢吃果冻。因此, 每个朋友带来的生日礼物全是一包果冻.。
在每个朋友送他一包果冻的同时,
栋栋还要这个朋友送他一个幸运号码 L(1≤ L ≤ N)
。然后栋栋会先把这包果冻放在一旁,并且把之前的所有果冻包按照果冻的数量从小到大排序(如果果冻数量相等,先后顺序任意)。接着,栋栋再把
当前这包果冻插入到有序的果冻包队列中,使得这个队列仍然有序(如果存在其他的果冻包与该果冻包数量相等,则把该果冻包放在它们的前面)。完成这个操作后,栋栋就会进行如下操作 :
·如果这个朋友是男生,栋栋会从他送的包的后一个包开始向后数 L 个
(该朋友的幸运号码),从那个包里取出一个果冻,吃掉。
·如果这个朋友是女生,栋栋会从她送的包的前一个包开始向前数 L 个
(该朋友的幸运号码),从那个包里取出一个果冻,吃掉。
栋栋实在是太粗心了,以至于他收完所有的礼物后,都不知道吃过哪些朋友
的果冻,现在,他希望你帮他一下,当他每吃一个果冻后马上告诉他可能吃的是
谁送的(由于排序不是确定的,所以栋栋只要你给他一种可能的答案就行了)。
这是一个交互式的题目,你必须调用库函数来完成所有操作而不能访问任何
文件。
对于 Pascal 的用户:
1.使用库
你必须引用 happybirthday_lib_p 单元,并在源代码的第一行加入
uses happybirthday_lib_p;
2.库函数
init:
定义:procedure init;
调用:init;
说明:这个函数在你的程序中必须调用且仅调用一次,它的功能是初始化库。
getpresent:
定义:function getpresent(var count: longint; var luckynumber: longint; var isboy:
boolean): boolean;
调用:isend := getpresent(count, luckynumber, isboy);
其中 count 和 luckynumber 是两个长整型的变量,isboy 和 isend 是两个布尔型变
说明:这个函数用来获得下一个朋友的礼物,count 表示礼物包中果冻的个数,
lukcynumber 是这个朋友给栋栋的幸运数字 L,
isboy 用来标志这个朋友的性
别,如果是 true,表示是男生,否则表示是女生。
如果后面还有朋友要送给栋栋礼物,函数返回 true,否则返回 false,此时
你的程序应当结束运行。
tell:
定义:procedure tell(const friendid: longint);
调用:tell(friendid);
其中 friendid 可以是任何可以计算出长整型结果的表达式。
说明:这个函数用来告诉栋栋刚才吃的是第几个朋友送的果冻。如果这个朋友不
存在,或者该朋友送的果冻包内已无果冻,则 friendid 应为-1。
每调用一次 getpresent,如果返回值是 true,必须调用一次 tell。
blockmsg:
定义:procedure blockmsg;
调用:blockmsg;
说明:这是一个为了方便调试而附加的函数。因为写文件的速度较慢,利用此函
数可以屏蔽库写调用的相关信息,以便于进行速度测试。在实际测试过程中,这
个函数将被定义为一个空函数,你的程序中可以有任意次数对该函数的调用,你
不必担心因这个函数而影响程序的正确性和速度。
对于 C++的用户:
1.使用库
你必须使用 happybirthday_lib_c 库,并在源代码中加入
#include “happybirthday_lib_c.h”
并在工程加入 happybirthday_lib_c.o。
2.库函数
init:
定义:void init();
调用:init();
说明:这个函数在你的程序中必须调用且仅调用一次,它的功能是初始化库。
getpresent:
定义:bool getpresent(long &count, long &luckynumber, bool &isboy);
调用:isend = getpresent(count, luckynumber, isboy);
其中 count 和 luckynumber 是两个长整型的变量,isboy 和 isend 是两个布尔型变
量。
说明:这个函数用来获得下一个朋友的礼物,count 表示礼物包中果冻的个数,
lukcynumber 是这个朋友给栋栋的幸运数字 L,
isboy 用来标志这个朋友的性
别,如果是 true,表示是男生,否则表示是女生。
如果后面还有朋友要送给栋栋礼物,函数返回 true,否则返回 false,此时
你的程序应当结束运行。
tell:
定义:void tell(const long friendid);
调用:tell(friendid);
其中 friendid 可以是任何可以计算出长整型结果的表达式。
说明:这个函数用来告诉栋栋刚才吃的是第几个朋友送的果冻。如果这个朋友不
存在,或者该朋友送的果冻包内已无果冻,则 friendid 应为-1。
每调用一次 getpresent,如果返回值是 true,必须调用一次 tell。
blockmsg:
定义:void blockmsg();
调用:blockmsg();
说明:这是一个为了方便调试而附加的函数。因为写文件的速度较慢,利用此函
数可以屏蔽库写调用的相关信息,以便于进行速度测试。在实际测试过程中,这
个函数将被定义为一个空函数,你的程序中可以有任意次数对该函数的调用,你
不必担心因这个函数而影响程序的正确性和速度。
【如何测试自己的程序】
为了测试自己的程序,你应该在程序所在的目录中建立一个名为
happybirthday.in 的文件。文件格式如下:
文件的第一行为一个整数 n,表示送给栋栋礼物的朋友个数。
接下来 n 行,每行三个整数,总第 i+1 行的三个整数分别表示第 i 个朋友送
的果冻包内的果冻个数、幸运数字以及这个朋友的性别,如果是男生,性别用数
字 1 表示,如果是女生,性别用 0 表示。
如果你的目录下有这个文件,库将从这个文件里面读入礼物的信息,并把结
果输出到 happybirthday.out 中,里面可能有如下的信息:
·call init():调用函数 init
·Error: recall init():已经调用过 init,又重复调用
·Error: not init:调用其他函数前没有调用 init
·getpresent: **:调用 getpresent,后面的**是函数的返回信息
·god bless:调用 getpresent,所有的礼物都已经处理完,如果你的一切调用都
正确,这句话应该是 happybirthday.out 的最后一句
·Error: no present left:调用 getpresent 返回 false 后,又调用了 getpresent
·Error: not told yet:两次 getpresent 之间没有调用 tell
·tell: **:调用 tell,后面的**是函数的参数信息
·Error: ear overflow:连续调用 tell,在没调用 getpresent 的情况下调用 tell 或者
getpresent 返回 false 后调用 tell
在测试自己的程序的时候,你必须保证你的输入文件是按照给定格式的,否
则可能会出现运行异常。
【数据规模和约定】
对于所有的数据,
我们保证: ≤ n ≤ 500000, ≤ count ≤ 108, 1 ≤ luckynumber≤ n.在测试时,你的数据也应该满足我们的数据范围,否则有可能运行异常。
【评分方法】
如果你的程序出现如下情况,该测试点 0 分:
访问了任何文件(包括临时文件)
;
非法调用库函数;
让测试库异常退出;
答案错误。
否则该测试点得满分。
【样例】
happybirthday.in
3
32 1 1
1 1 1
23 1 0
Pascal 源程序
uses
happybirthday_p;
var
count, luckynumber: longint;
isboy: boolean;
begin
init;
getpresent(count, luckynumber, isboy);
tell(-1);
getpresent(count, luckynumber, isboy);
tell(1);
getpresent(count, luckynumber, isboy);
tell(2);
getpresent(count, luckynumber, isboy);
end.
C++源程序
#include "happybirthday_cpp.h"
long count, luckynumber;
bool isboy;
int main()
{
init();
getpresent(count, luckynumber,
tell(-1);
getpresent(count, luckynumber,
tell(1);
getpresent(count, luckynumber,
tell(2);
getpresent(count, luckynumber,
return 0;
}
isboy);
isboy);
isboy);
isboy);
运行后,库将生成如下信息在 happybirthday.out 中
call init()
getpresent: count=32,luckynumber=1,isboy=true Return true
tell: -1
getpresent: count=1,luckynumber=1,isboy=true Return true
tell: 1
getpresent: count=23,luckynumber=1,isboy=false Return true
tell: 2
getpresent: Return false
god bless

 

题解

 

splay
  1 (*
  2     *Problem:    NOI2006 生日快乐
  3     *Author :    Chen Yang
  4     *Time   :    2012.5.31 2:00 pm
  5     *State  :    Solved
  6     *Memo   :    splay
  7 *)
  8 program happybirthday;
  9 uses happybirthday_lib_p;
 10 var
 11   n,luky,cnt,root,t,i:longint;
 12   isboy:boolean;
 13   s,l,r,father,v,num:array[0..1000000] of longint;
 14 //===================
 15 procedure l_rotate(x:longint);     inline;
 16 var
 17   y,z:longint;
 18 begin
 19   y:=r[x]; z:=father[x];
 20   if x=l[z] then l[z]:=y else
 21   if x=r[z] then r[z]:=y;
 22   father[y]:=z; father[l[y]]:=x; father[x]:=y;
 23   r[x]:=l[y]; l[y]:=x; father[0]:=0;
 24   s[x]:=s[l[x]]+s[r[x]]+1; s[y]:=s[l[y]]+s[r[y]]+1;
 25 end;
 26 //===================
 27 procedure r_rotate(x:longint);     inline;
 28 var
 29   y,z:longint;
 30 begin
 31   y:=l[x]; z:=father[x];
 32   if x=l[z] then l[z]:=y else
 33   if x=r[z] then r[z]:=y;
 34   father[y]:=z; father[r[y]]:=x; father[x]:=y;
 35   l[x]:=r[y]; r[y]:=x; father[0]:=0;
 36   s[x]:=s[l[x]]+s[r[x]]+1; s[y]:=s[l[y]]+s[r[y]]+1;
 37 end;
 38 //===================
 39 procedure splay(x,p:longint);
 40 var
 41   y,z:longint;
 42 begin
 43   z:=father[p];
 44   while father[x]<>z do
 45   begin
 46     y:=father[x];
 47     if x=l[y] then r_rotate(y) else l_rotate(y);
 48   end;
 49   if p=root then root:=x;
 50 end;
 51 //===================
 52 function insert(var k:longint; t,x,fa:longint):longint;
 53 begin
 54   if k=0 then
 55   begin
 56     inc(n);
 57     v[n]:=t; s[n]:=1; father[n]:=fa; num[n]:=x;
 58     l[n]:=0; r[n]:=0;
 59     k:=n; exit(n);
 60   end;
 61   inc(s[k]);
 62   if t<=v[k] then exit(insert(l[k],t,x,k)) else exit(insert(r[k],t,x,k));
 63 end;
 64 //===================
 65 procedure delete(x:longint);
 66 var
 67   i:longint;
 68 begin
 69   splay(x,root);
 70   i:=l[root];
 71   if i>0 then
 72   begin
 73     while r[i]>0 do i:=r[i];
 74     splay(i,l[root]);
 75     r[i]:=r[root];
 76     father[r[i]]:=i;
 77     s[i]:=s[root]-1;
 78     root:=i;
 79   end else root:=r[root];
 80   father[root]:=0;
 81 end;
 82 //===================
 83 function find(x,k:longint):longint;
 84 begin
 85   if x=0 then exit(-1);
 86   if s[l[x]]=k-1 then exit(x);
 87   if s[l[x]]>k-1 then exit(find(l[x],k));
 88   exit(find(r[x],k-s[l[x]]-1));
 89 end;
 90 //===================
 91 begin
 92   init; root:=0; i:=0;
 93   blockmsg;
 94   while getpresent(cnt,luky,isboy) do
 95   begin
 96     inc(i);
 97     splay(insert(root,cnt,i,0),root);
 98     if isboy then t:=find(r[root],luky)
 99     else t:=find(l[root],s[l[root]]-luky+1);
100     if t>0 then
101     begin
102       delete(t); dec(v[t]);
103       if v[t]>0 then insert(root,v[t],num[t],0);
104     end;
105     if t>0 then tell(num[t]) else tell(-1);
106   end;
107 end.

 

treap变成的排序二叉树
 1 (*
 2     *Problem:    NOI2006 生日快乐
 3     *Author :    Chen Yang
 4     *Time   :    2012.5.31 2:00 pm
 5     *State  :    Solved
 6     *Memo   :    treap(被卡,于是)取消左右旋——排序二叉树
 7 *)
 8 program happybirthday;
 9 uses happybirthday_lib_p;
10 const maxn=1000100;
11 var
12   n,m,luck,cnt,root,rak,t:longint;
13   isboy:boolean;
14   s,l,r,num,v:array[0..maxn] of longint;
15 //=========================
16 procedure insert(var k:longint; p:longint);
17 begin
18   if k=0 then
19   begin
20     inc(m);
21     s[m]:=1; num[m]:=p; k:=m;
22     exit;
23   end;
24   inc(s[k]);
25   if v[p]<=v[num[k]] then insert(l[k],p)
26   else begin
27     inc(rak,s[l[k]]+1);
28     insert(r[k],p);
29   end;
30 end;
31 //=========================
32 function sele(var k:longint; t:longint):longint;
33 begin
34   if k=0 then exit(-1);
35   if s[l[k]]=t-1 then
36   begin
37     sele:=num[k];
38     if (l[k]=0)or(r[k]=0) then
39     begin
40       k:=l[k]+r[k];
41       exit;
42     end;
43     num[k]:=sele(l[k],s[l[k]]);
44     dec(s[k]);
45     exit;
46   end;
47   dec(s[k]);
48   if s[l[k]]>t-1 then exit(sele(l[k],t)) else exit(sele(r[k],t-s[l[k]]-1));
49 end;
50 //=========================
51 begin
52   init; n:=0; root:=0;
53   while getpresent(cnt,luck,isboy) do
54   begin
55     inc(n); rak:=1; v[n]:=cnt;
56     insert(root,n);
57     if isboy then inc(rak,luck) else dec(rak,luck);
58     if (rak<=s[root])and(rak>0) then t:=sele(root,rak) else t:=-1;
59     if t>0 then
60     begin
61       dec(v[t]); if v[t]>0 then insert(root,t);
62     end;
63     tell(t);
64   end;
65 end.

转载于:https://www.cnblogs.com/datam-cy/archive/2012/06/02/NOI2006-happybirthday.html

已标记关键词 清除标记
表情包
插入表情
评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符
相关推荐
<p> <span style="color:#337FE5;"><strong>【为什么还需要学习C++?】</strong></span> </p> <p style="margin-left:0cm;"> 你是否接触很多语言,但从来没有了解过编程语言的本质? </p> <p style="margin-left:0cm;text-align:start;"> 你是否想成为一名资深开发人员,想开发别人做不了的高性能程序? </p> <p style="margin-left:0cm;text-align:start;"> 你是否经常想要窥探大型企业级开发工程的思路,但苦于没有基础只能望洋兴叹? </p> <p style="margin-left:0cm;text-align:start;">   </p> <p style="margin-left:0cm;text-align:start;"> 那么C++就是你个人能力提升,职业之路进阶的不二之选。 </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p style="margin-left:0cm;"> <strong><span style="color:#337FE5;">【课程特色】</span></strong> </p> <p style="margin-left:0cm;text-align:start;"> 1.课程共19大章节,239课时内容,涵盖数据结构、函数、类、指针、标准库全部知识体系。 </p> <p style="margin-left:0cm;text-align:start;"> 2.带你从知识与思想的层面从0构建C++知识框架,分析大型项目实践思路,为你打下坚实的基础。 </p> <p style="margin-left:0cm;text-align:start;"> 3.李宁老师结合4大国外顶级C++著作的精华为大家推出的《征服C++11》课程。 </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p class="ql-long-24357476"> <span style="color:#337FE5;"><strong>【学完后我将达到什么水平?】</strong></span> </p> <p class="ql-long-24357476"> 1.对C++的各个知识能够熟练配置、开发、部署; </p> <p class="ql-long-24357476"> 2.吊打一切关于C++的笔试面试题; </p> <p class="ql-long-24357476"> 3.面向物联网的“嵌入式”和面向大型化的“分布式”开发,掌握职业钥匙,把握行业先机。 </p> <p class="MsoNoSpacing" style="margin-left:18pt;"> <br /> </p> <div> <br /> </div> <p> <br /> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#337FE5;"><strong>【面向人群】</strong></span> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#222226;font-family:PingFangSC-Regular, "font-size:14px;background-color:#FFFFFF;">1.希望一站式快速入门的C++初学者;</span> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#222226;font-family:PingFangSC-Regular, "font-size:14px;background-color:#FFFFFF;">2.希望快速学习 C++、掌握编程要义、修炼内功的开发者;</span> </p> <p style="margin-left:0cm;text-align:start;"> <span style="color:#222226;font-family:PingFangSC-Regular, "font-size:14px;background-color:#FFFFFF;">3.有志于挑战更高级的开发项目,成为资深开发的工程师。</span> </p> <p style="margin-left:0cm;text-align:start;"> <br /> </p> <p> <br /> </p> <p> <span style="color:#337FE5;"><strong>【课程设计】</strong></span> </p> <p> 本课程包含3大模块 </p> <p> <strong>基础篇</strong><br /> 本篇主要讲解c++的基础概念,包含数据类型、运算符等基本语法,数组、指针、字符串等基本词法,循环、函数、类等基本句法等。 </p> <p> <br /> <strong>进阶篇</strong><br /> 本篇主要讲解编程中常用的一些技能,包含类的高级技术、类的继承、编译链接和命名空间等。 </p> <p> <br /> <strong>提升篇:</strong><br /> 本篇可以帮助学员更加高效的进行c++开发,其中包含类型转换、文件操作、异常处理、代码重用等内容。 </p> <p> <img src="https://img-bss.csdnimg.cn/202007091130239667.png" alt="" /> </p>
百度云盘分享 简介 笔者当初为了学习JAVA,收集了很多经典源码,源码难易程度分为初级、中级、高级等,详情看源码列表,需要的可以直接下载! 这些源码反映了那时那景笔者对未来的盲目,对代码的热情、执着,对IT的憧憬、向往!此时此景,笔者只专注Android、Iphone等移动平台开发,看着这些源码心中有万分感慨,写此文章纪念那时那景! Java 源码包 Applet钢琴模拟程序java源码 2个目标文件,提供基本的音乐编辑功能。编辑音乐软件的朋友,这款实例会对你有所帮助。 Calendar万年历 1个目标文件 EJB 模拟银行ATM流程及操作源代码 6个目标文件,EJB来模拟银行ATM机的流程及操作:获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除,从账户中取出amt,如果amt>账户余额抛出异常,一个实体Bean可以表示不同的数据实例,我们应该通过主键来判断删除哪个数据实例…… ejbCreate函数用于初始化一个EJB实例 5个目标文件,演示Address EJB的实现,创建一个EJB测试客户端,得到名字上下文,查询jndi名,通过强制转型得到Home接口,getInitialContext()函数返回一个经过初始化的上下文,用client的getHome()函数调用Home接口函数得到远程接口的引用,用远程接口的引用访问EJB。 EJB中JNDI的使用源码例子 1个目标文件,JNDI的使用例子,有源代码,可以下载参考,JNDI的使用,初始化Context,它是连接JNDI树的起始点,查找你要的对象,打印找到的对象,关闭Context…… ftp文件传输 2个目标文件,FTP的目标是:(1)提高文件的共享性(计算机程序和/或数据),(2)鼓励间接地(通过程序)使用远程计算机,(3)保护用户因主机之间的文件存储系统导致的变化,(4)为了可靠和高效地传输,虽然用户可以在终端上直接地使用它,但是它的主要作用是供程序使用的。本规范尝试满足大型主机、微型主机、个人工作站、和TACs 的不同需求。例如,容易实现协议的设计。 Java EJB中有、无状态SessionBean的两个例子 两个例子,无状态SessionBean可会话Bean必须实现SessionBean,获取系统属性,初始化JNDI,取得Home对象的引用,创建EJB对象,计算利息等;在有状态SessionBean中,用累加器,以对话状态存储起来,创建EJB对象,并将当前的计数器初始化,调用每一个EJB对象的count()方法,保证Bean正常被激活和钝化,EJB对象是用完毕,从内存中清除…… Java Socket 聊天通信演示代码 2个目标文件,一个服务器,一个客户端。 Java Telnet客户端实例源码 一个目标文件,演示Socket的使用。 Java 组播组中发送和接受数据实例 3个目标文件。 Java读写文本文件的示例代码 1个目标文件。 java俄罗斯方块 一个目标文件。 Java非对称加密源码实例 1个目标文件 摘要:Java源码,算法相关,非对称加密   Java非对称加密源程序代码实例,本例中使用RSA加密技术,定义加密算法可用 DES,DESede,Blowfish等。   设定字符串为“张三,你好,我是李四”   产生张三的密钥对(keyPairZhang)   张三生成公钥(publicKeyZhang)并发送给李四,这里发送的是公钥的数组字节   通过网络或磁盘等方式,把公钥编码传送给李四,李四接收到张三编码后的公钥,将其解码,李四用张三的公钥加密信息,并发送给李四,张三用自己的私钥解密从李四处收到的信息…… Java利用DES私钥对称加密代码实例 同上 java聊天室 2个目标文件,简单。 java模拟掷骰子2个 1个目标文件,输出演示。 java凭图游戏 一个目标文件,简单。 java求一个整数的因子 如题。 Java生成密钥的实例 1个目标文件 摘要:Java源码,算法相关,密钥   Java生成密钥、保存密钥的实例源码,通过本源码可以了解到Java如何产生单钥加密的密钥(myKey)、产生双钥的密钥对(keyPair)、如何保存公钥的字节数组、保存私钥到文件privateKey.dat、如何用Java对象序列化保存私钥,通常应对私钥加密后再保存、如何从文件中得到公钥编码的字节数组、如何从字节数组解码公钥。 Java数据压缩与传输实例 1个目标文件 摘要:Java源码,文件操作,数据压缩,文件传输   Jav
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页