1746. 【usaco 2013 feb Bronze】粉刷栅栏(Painting the Fence)

USACO栅栏粉刷问题解析
本文解析USACO 2013 February Bronze级别竞赛中的栅栏粉刷问题,介绍了如何通过转化指令为区间并进行排序,使用类似挤牛奶的方法计算至少被粉刷两次的栅栏总长度。

1746. 【usaco 2013 feb Bronze】粉刷栅栏(Painting the Fence)

题目:
农夫约翰最近正在将他的栅栏粉刷一下(这里所有的栅栏都是在一条直线上的)。他是这样来粉刷的:他从位置0出发,然后执行N条指令,例如,指令可以是“10 L”,表示约翰从当前的位置向左移动10个单位的距离,并且粉刷移动过程中遇到的栅栏,又或者是“15 R”,表示约翰从当前的位置向右移动15个单位的距离,并且粉刷移动过程中遇到的栅栏。
   给定所有约翰需要移动的指令,请计算所有栅栏中至少被粉刷两次的栅栏的总长度。约翰最多远离初始位置1000000000个单位的距离。
输入:
第一行一个正整数N。

接下来第2行到第N+1行,每行表示每条指令。
输出:
只有一行一个整数,表示所有栅栏中至少被粉刷两次的栅栏的总长度。
数据范围:
1<=N<=100000。


这就是道水题啊!
我们将指令全部转化为区间
排个序(我怕被卡,打了个堆排)
然后按照usaco挤牛奶的方法做
每次将当前区间与上一个区间的交集累加进答案
然后更新当前区间

比赛时信心满满
20分钟码完
一看成绩(10分)
傻眼
赛后听讲,发现正解和我的方法完全一样
百思不得其解
先是检查了排序
又看数据范围
最后才发现少打了几个判断
改完,AC

标程:
var     ch,kong:char;
        a,d:array[0..100000,1..2]of longint;
        n,i,x,j,k,l,s,m,ans,len,head,tail:longint;
        bz:array[1..100000]of longint;
procedure up(t:longint);
var     x,y:longint;
begin
        x:=t;
        while(x>1)and((d[x div 2,1]>d[x,1])or(d[x div 2,1]=d[x,1])and(d[x div 2,2]>d[x,2]))do
        begin
                y:=x div 2;
                d[0]:=d[x];
                d[x]:=d[y];
                d[y]:=d[0];
                x:=y;
        end;
end;
procedure down(t:longint);
var     x,y:longint;
begin
        x:=t;
        while((x*2<=len)and((d[x*2,1]<d[x,1])or(d[x*2,1]=d[x,1])and(d[x*2,2]<d[x,2])))or
        ((x*2+1<=len)and((d[x*2+1,1]<d[x,1])or(d[x*2+1,1]=d[x,1])and(d[x*2+1,2]<d[x,2])))do
        begin
                y:=x*2;
                if(d[y+1,1]<d[y,1])or(d[y+1,1]=d[y,1])and(d[y+1,2]<d[y,2])then inc(y);
                d[0]:=d[x];
                d[x]:=d[y];
                d[y]:=d[0];
                x:=y;
        end;
end;
procedure insert(t:longint);
begin
        inc(len);
        d[len]:=a[t];
        up(len);
end;
procedure dsort;
begin
        for i:=1 to n do
                insert(i);
        a[1]:=d[1];
        for i:=2 to n do
        begin
                d[1]:=d[len];
                dec(len);
                down(1);
                a[i]:=d[1];
        end;
end;

function max(a,b:longint):longint;
begin if a>b then max:=a else max:=b; end;
begin
        assign(input,'paint.in');
        assign(output,'paint.out');
        reset(input);
        rewrite(output);
        readln(n);
        x:=0;
        for i:=1 to n do
        begin
                readln(s,kong,ch);
                if ch='R' then
                begin
                        a[i,1]:=x;
                        a[i,2]:=x+s;
                        x:=x+s;
                end;
                if ch='L' then
                begin
                        a[i,1]:=x-s;
                        a[i,2]:=x;
                        x:=x-s;
                end;
        end;
        dsort;
        head:=a[1,1];
        tail:=a[1,2];
        ans:=0;
        for i:=2 to n do
        begin
                if a[i,2]<=head then continue;
                if(a[i,2]<=tail)then
                begin
                        ans:=ans+(a[i,2]-max(a[i,1],head));
                        head:=a[i,2]
                end
                else
                if a[i,1]>=tail then
                begin
                        head:=a[i,1];
                        tail:=a[i,2]
                end
                else
                if a[i,1]<=head then
                begin
                        ans:=ans+(tail-head);
                        head:=tail;
                        tail:=a[i,2]
                end
                else
                begin
                        ans:=ans+(tail-a[i,1]);
                        head:=tail;
                        tail:=a[i,2];
                end;
        end;
        writeln(ans);
        close(input);
        close(output);
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值