主题:[讨论]给大家一道题连连笔
mmsxzy
[专家分:440] 发布于 2005-11-08 18:43:00
狗狗大决杀
时间限制:1S
空间限制:32M
文件名:line.pas
输入文件:line.in
输出文件:line.out
语言:freepascal/C++/C
【题目描述】
这是10月32日发生的事情。抽筋流高手布置了一个非常BT的作业。他说要在一定时间内把屏幕上的所有小狗布成一条直线。而这个时间非常之短!!!众人大呼BT,但是抽筋流高手是非常严格的,所以大家只好遵从他的命令。
众所周知,只有达达的APM在190以上,所以最后完成作业的只有他一个。他受到了抽筋流高手的表扬。
然而罗小松觉得不爽,于是他趁达达去WC的时候在那一条直线上放了一系列机枪兵,对可爱的狗狗们进行了残忍的屠杀。
已知每个机枪兵有一定的射程。然而这是一种特殊的星际版本,机枪升攻击的时候也可以升射程!所以每个机枪的射程不一定相同。现在一列狗兵(zerging)排成直线,每一次一个机枪兵打掉一定范围内的所有狗狗,每个狗狗有一个编号,每次给出一个杀伤区间,其中的小狗将会被全部杀掉。最后,让你统计一共杀了多少个。
简而言之,给出数轴上N条线段,每条线段用两个数表示A , B(-10^9<=A<B<=10^9),表示从a到b的一条线段。现在请求出它们覆盖数轴上的多长距离。
【输入数据】
第一行:N
以后N行,每行两个数:Ai Bi
【输出数据】
一个数,表示覆盖长度
【样例输入】
3
2 8
-1 1
5 10
【样例输出】
10
【数据范围】
对于10%的数据N<=20;
对于30%的数据N<=1000;
对于100%的数据N<=20000;
回复列表 (共10个回复)
沙发
ggggqqqqihc [专家分:540] 发布于 2005-11-08 19:31:00
似乎没什么技巧,模拟就行了。不过32MB的内存……
板凳
agilewang [专家分:0] 发布于 2005-11-08 22:32:00
支持1楼的看法~!
3 楼
ggggqqqqihc [专家分:540] 发布于 2005-11-08 23:55:00
我是想说32MB的内存是不是太多了?
先按线段左端点的位置排序,然后按次序加入线段。每加入一条线段,都去和已经加入的线段比较,若有相交的,就去掉相交的那部分,最后只看剩下的长度就行了。先排序是为了避免后面加入的线段被截成好几节。至于判断相交的方法就不用说了吧!
不过当N=20000时似乎有点悬,大家有没有更好的方法?32MB内存呀!
4 楼
mythjoker [专家分:400] 发布于 2005-11-10 07:45:00
题目读的我眼晕!
不过,答案SO easy.
5 楼
ggggqqqqihc [专家分:540] 发布于 2005-11-10 12:02:00
答案恐怕没有那么简单。刚才我给出的是O(n^2)的算法,时间怕是不够。参考[url=http://oibh.kuye.cn/download/thesis/thesis99_chenhong.zip]陈宏的论文[/url]用线段树做了一下,这回复杂度是O(nlogn),应该是比较圆满地解决了。
var
a:array[1..40000] of longint;
Type
PLines_Tree=^Lines_Tree;
Lines_Tree=Object
i,j:longint;
count:integer;
leftchild,rightchild:PLines_Tree;
M:longint;
Procedure Build(l,r:longint);
Procedure Insert(l,r:longint);
Procedure Update;
end;
Segment=record
l,r:longint;
end;
Procedure Lines_Tree.Build(l,r:longint);
var
k:longint;
begin
i:=l;
j:=r;
count:=0;
if r-1>l then
begin
k:=(l+r) div 2;
new(leftchild);
leftchild^.Build(l,k);
new(rightchild);
rightchild^.Build(k,r);
end
else
begin
leftchild:=nil;
rightchild:=nil;
end;
end;
Procedure Lines_Tree.Insert(l,r:longint);
begin
if (l<=a[i]) and (r>=a[j]) then
inc(count)
else
begin
if l<a[(i+j) div 2] then leftchild^.Insert(l,r);
if r>a[(i+j) div 2] then rightchild^.Insert(l,r);
end;
end;
Procedure Lines_Tree.Update;
begin
if count>0 then
M:=a[j]-a[i]
else
begin
if j-i=1 then
M:=0
else
begin
leftchild^.Update;
rightchild^.Update;
M:=leftchild^.M+rightchild^.M;
end;
end;
end;
var
seg:array[1..20000] of Segment;
Tree:Lines_Tree;
n,i:integer;
Procedure Swap(var a,b:longint);
var
t:longint;
begin
t:=a;
a:=b;
b:=t;
end;
Function Partition(p,r:longint):longint;
var
i,j:longint;
begin
i:=p-1;
for j:=p to r-1 do
if a[j]<a[r] then
begin
inc(i);
Swap(a[i],a[j]);
end;
Swap(a[i+1],a[r]);
Partition:=i+1;
end;
Procedure Qsort(p,r:longint);
var
q:longint;
begin
if p<r then
begin
q:=Partition(p,r);
Qsort(p,q-1);
Qsort(q+1,r);
end;
end;
begin
assign(input,'lines.in');
reset(input);
read(n);
for i:=1 to n do
begin
read(seg[i].l,seg[i].r);
a[i*2-1]:=seg[i].l;
a[i*2]:=seg[i].r;
end;
Qsort(1,2*n);
Tree.Build(1,2*n);
for i:=1 to n do
begin
Tree.Insert(seg[i].l,seg[i].r);
Tree.Update;
end;
writeln(Tree.M);
close(input);
end.
6 楼
479686 [专家分:150] 发布于 2005-11-10 13:10:00
汗~ 重庆一中的模拟题。。。
7 楼
479686 [专家分:150] 发布于 2005-11-10 13:21:00
[url]http://upload.programfan.com/upfile/200511101319919.rar[/url]
给你标程~
8 楼
ggggqqqqihc [专家分:540] 发布于 2005-11-10 21:17:00
谢谢楼上的,我的程序已经确认AC了。
9 楼
沐宇春风 [专家分:0] 发布于 2005-11-15 21:09:00
师傅,你是我的偶像!!!1
好有创意的题哦!!!
10 楼
mythjoker [专家分:400] 发布于 2005-12-03 18:21:00
很像普及组第二题,
不过这个天上,那个地下!!!
我来回复