具体内容参看原题。
停牛们说这是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的路程,实现了一个质的飞跃!
代码如下:
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] < x do inc(i);
11 while a[j] > x do dec(j);
12 if i <= j 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 > l then qsort(l,j);
19 if i < r 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] > l do dec(m);
28 if s = t 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: = s to l + t do
55 for j: = t 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: = l to l + t do
61 begin
62 if f[i] < count then
63 count: = f[i];
64 end ;
65 end ;
66 writeln(count);
67
68 end .