回 帖 发 新 帖 刷新版面

主题:[讨论]给大家一道题连连笔

狗狗大决杀

时间限制: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个回复)

沙发

似乎没什么技巧,模拟就行了。不过32MB的内存……

板凳

支持1楼的看法~!

3 楼

我是想说32MB的内存是不是太多了?
先按线段左端点的位置排序,然后按次序加入线段。每加入一条线段,都去和已经加入的线段比较,若有相交的,就去掉相交的那部分,最后只看剩下的长度就行了。先排序是为了避免后面加入的线段被截成好几节。至于判断相交的方法就不用说了吧!

不过当N=20000时似乎有点悬,大家有没有更好的方法?32MB内存呀!

4 楼

题目读的我眼晕!
不过,答案SO easy.

5 楼

答案恐怕没有那么简单。刚才我给出的是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 楼

汗~ 重庆一中的模拟题。。。

7 楼

[url]http://upload.programfan.com/upfile/200511101319919.rar[/url]
给你标程~

8 楼

谢谢楼上的,我的程序已经确认AC了。

9 楼

师傅,你是我的偶像!!!1
好有创意的题哦!!!

10 楼

很像普及组第二题,
不过这个天上,那个地下!!!

我来回复

您尚未登录,请登录后再回复。点此登录或注册