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 .

 

转载于:https://www.cnblogs.com/waterfalleagle/archive/2009/10/29/1591852.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值