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]<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.
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.