vj p1002题解

具体内容参看原题

停牛们说这是noip最难的一道DP,不知是不是真的,个人感觉没有多进程DP难。

我是这样做的:(当然,在大牛的帮助下)

DP方程很好想:

f[i]=f[i-k] or f[i],(k=s..t);

但是问题在于巨大的数据范围,对于30%的数据,L <= 10000;对于全部的数据,L <= 10^9。

所以这样做绝对挂掉。

仔细看,会发现石子数M的范围很小,1 <= M <= 100,如果以最大的数据来看,平均10^7的距离中有一颗石子,也就是说,在巨长的桥中间很散的分布着石子,而有这大段大段的空位置,甚至会出现在一段距离内,无论如何跳都踩不到石子的情况。

再发挥下我们的想象:科幻电影中不是有很多关于宇宙旅行的东西么?怎样进行超光速飞行呢?那么,就是进行虫洞跳跃!想到这,方法就出来了!那就是虫洞跳跃!事实上,就是DP状态压缩!

因为步长为s..t,而1 <= S <= T <= 10,

先讨论特殊情况:如果s=t,那么就不用DP,直接搜索即可。

如果S<T,

假设s=9,t=10,那么在90步后的任意一步,都可以用s和t的组合来达到:

如:要到91步,则9*s+t;同理,92:=8*s+2*t……

也就是说,如果s=t-1,那么必然能通过组合表示t*(t-1)后的数字。

推广开,就是当一个数k>t*(t-1)时,那么k必然可以用t和一个比t小而比s大的数表示。

证毕!

证明这个有什么用呢?当然有用了,这就是进行“空间跳跃”的基础!

如果两个石子之间的空格超过了t*(t-1)那么就直接把这两段之间连个虫洞,中间的距离省掉。

这样压缩后的结果就是将10^9的路程压缩成了最大100*90的路程,实现了一个质的飞跃!

代码如下:

 

 1 var count,s,j,i,t,m,l,ls:longint;a,b,c:array[0..200]of longint;
 2     f:array[0..100000]of longint;
 3     v:array[0..100000]of boolean;
 4 procedure qsort(l,r:longint);
 5   var i,j,t,x:longint;
 6   begin
 7     i:=l;j:=r;
 8     x:=a[(i+j)div 2];
 9     repeat
10       while a[i]<do inc(i);
11       while a[j]>do dec(j);
12       if i<=then
13         begin
14           t:=a[i];a[i]:=a[j];a[j]:=t;
15           inc(i);dec(j);
16         end;
17     until i>j;
18     if j>then qsort(l,j);
19     if i<then qsort(i,r);
20   end;
21 begin
22   
23   readln(l);
24   readln(s,t,m);
25   for i:=1 to m do read(a[i]);
26   qsort(1,m);
27   while a[m]>do dec(m);
28   if s=then
29     begin
30       count:=0;
31       for i:=1 to m do
32         begin
33           if a[i] mod s=0 then inc(count);
34         end;
35     end
36   else
37     begin
38       a[0]:=0;
39       b[0]:=0;
40       ls:=t*(t-1);
41       fillchar(v,sizeof(v),0);
42       for i:=1 to m do
43         begin
44           if a[i]-a[i-1]>ls then
45             begin
46               b[i]:=b[i-1]+ls;
47             end
48           else b[i]:=b[i-1]+a[i]-a[i-1];
49           v[b[i]]:=true;
50         end;
51       if l-b[m]>ls then l:=b[m]+ls;
52       fillchar(f,sizeof(f),100);
53       f[0]:=0;
54       for i:=to l+do
55         for j:=downto s do if i-j>=0 then
56           begin
57             if f[i-j]+ord(v[i-j])<f[i] then f[i]:=f[i-j]+ord(v[i-j]);
58           end;
59       count:=maxlongint;
60       for i:=to l+do
61         begin
62           if f[i]<count then
63             count:=f[i];
64         end;
65     end;
66   writeln(count);
67   
68 end.

 

posted @ 2009-10-29 09:27  瀑布飞鹰  阅读(159)  评论(0编辑  收藏  举报