TYVJ1059(过河)-NOIP2005

算法:DP+压缩
本题难的不是DP方程,而是难在了压缩路径上面,首先,DP方程是很好想出的,每次跳的范围只能在[S,T]之间,所以到某一个位置时,只要从前面的[S,T]这个位置找一个最小值转移过来就行了,在判断一下这个点有没有石子,有就+1,否则直接转移。
但是一看数据范围,10^9,好吧,裸方法可以去使了……
仔细观察题目数据不难看出虽然总长度是10^9,但是石子最多却只有100个,这说明了什么?说明在这条路上石子出现是很稀疏的,这就可以用到了压缩路径的办法。
经过一系列的数学证明可以得出,当两个石子之间的距离大于100之后,两个石子之间的空隙跟空隙为100的最优值没有差别(因为S和T的范围也很小),这样就把一个极大的空隙变成了一个在100以内的空隙。也就是相当于我们把独木桥变短了。

最后还有一种情况就是S=T时,这时每次能跳的情况只有一种,就从起点累计一遍,mod S=0就把ans+1,输出ans。

program P1059;

const
  maxn=100;
  maxm=10000;

var
  l,s,t,m:longint;
  stone:array [0..maxn] of longint;{stone[i]表示第i颗石子的位置。}
  a,f:array [0..maxm] of longint;{a[i]表示压缩之后的i位置上有没有石子,有就是1,没有就是0。f[i]表示走到当前这个点最少踩到多少个石子。}
  
procedure doit;
var
  tans,i:longint;
begin
  tans:=0;
  for i:=1 to m do if stone[i] mod s=0 then inc(tans);
  writeln(tans);
  halt;
end;

procedure sort;{把石子的位置排一下序,因为石子数小于等于100,因此选择排序就可以了。}
var
  i,j,temp:longint;
begin
  for i:=1 to m-1 do
    begin
      for j:=i+1 to m do
        begin
          if stone[i]>stone[j] then
            begin
              temp:=stone[i];
              stone[i]:=stone[j];
              stone[j]:=temp;
            end;
        end;
    end;
end;

procedure init;
var
  i:longint;
begin
  readln(l);
  readln(s,t,m);
  for i:=1 to m do read(stone[i]);
  if s=t then doit;
end;

procedure main_1;
var
  i,t,last:longint;
begin
  last:=0;
  sort;
  for i:=1 to m do
    begin
      if stone[i]-stone[i-1]>100 then t:=100 else t:=stone[i]-stone[i-1];{如果小于100,就不能再压缩路径了。}
      a[last+t]:=1;{last+t即是当前石子的位置。}
      inc(last,t);{同时last也进行更新。}
    end;
  if l-a[m]>100 then t:=100 else t:=l-a[m];{处理独木桥总长度和最后一颗石子之间的位置关系。}
  l:=last+t;{同时把独木桥的长度也缩短了。}
end;

function min(x,y:longint):longint;
begin
  if x<y then exit(x) else exit(y);
end;

procedure main_2;
var
  i,j,ans:longint;
begin
  fillchar(f,sizeof(f),100);
  f[0]:=0;
  for i:=s to l+t-1 do{最后一次跳的位置距离终点最近也就1个单位长度,所以最后一个位置应该是l+t-1。而第一次跳最近是到s位置。}
    begin
      for j:=t downto s do{t是一个大数,让一个数减大数,所得即为小数,因此从小往大求。}
        begin
          if i-j>=0 then
          f[i]:=min(f[i],f[i-j]+a[i]);{从i-j位置跳到i位置,看i位置上有没石子,然后打擂台进行更新。}
        end;
    end;
  ans:=maxlongint;
  for i:=l to l+t-1 do if f[i]<ans then ans:=f[i];{搜索最小值,输出。}
  writeln(ans);
end;

begin
  assign(input,'P1059.in'); reset(input);
  assign(output,'P1059.out'); rewrite(output);
  
  init;
  main_1;
  main_2;
  
  close(input); close(output);
end.


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值