過河 解題報告
【問題描述】
在河上有一座獨木橋,乙隻青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點:0,1,……,l(其中l是橋的長度)。座標為0的點表示橋的起點,座標為l的點表示橋的終點。青蛙從橋的起點開始,不停的向終點方向跳躍。一次跳躍的距離是s到t之間的任意正整數(包括s,t)。當青蛙跳到或跳過座標為l的點時,就算青蛙已經跳出了獨木橋。
題目給出獨木橋的長度l,青蛙跳躍的距離範圍s,t,橋上石子的位置。你的任務是確定青蛙要想過河,最少需要踩到的石子數。其中l<=10^9,石子數m<=1000,1<=s<=t<=10;
【分析】
這道題直接搜尋顯然是不可行的,必然tle,考慮動態規劃:
opt[n]:=min(s<=i<=t) //rock[n]表示當前位置有沒有石子。
時間複雜度是o(n),對於小於等於10^9的l顯然是不可行的,於是我們可以嘗試進行優化。如此大的長度,而石子數卻只有1000,說明中間必然有很大的空白,可以將其壓縮。
我們先看乙個方程。px+(p+1)y=q(採用跳躍距離p和p+1時跳至位置q)因為p和p+1相隔1,所以當q>=p(p-1)時該方程必然有整數解(可以用同餘的思想證明:p mod (p+1)=-1;設q mod (p+1)=-k (k>0) ,則當x=k時,(p+1)y=q-px,mod (p+1)必然為0,此時y為非負整數。命題得證)。這就意味著如果跳躍距離如果不小於s(s-1),且s不等於t,那麼必然可以跳到,這樣便可以實現壓縮,以石子為狀態動態規劃。
好了,切入正題,說怎麼做吧。我們用b[i]為能否用s到t的一次跳躍距離跳至i遠的標誌(當s<=i<=th或i=0時為真),c[v]為青蛙能否跳到相對距離為v遠的標誌(v≤90)。
則當v<0時,c[v]:=0;
當v>=s(s-1)時,c[v]:=true;
當1<=s<=s(s-1)時,c[v]:=b[v];
(s=t時需特殊處理)
a[i,j]為青蛙跳至x[i]左方相對距離為j的位置時所經過的最少石子總數。若j=0,說明青蛙踩到了橋上的第i個石子。初始時,a[i,j]=n+1(0≤i≤n,0≤j≤t-1)。 第1種情況:x[i]-j位置位於x[i-1]的左方,即x[i]-j≤x[i-1]顯然,跳至x[i]-j位置經過的最少石子總數為a[i-1,j-x[i]+x[i-1]]。第2種情況:x[i]-j位置位於x[i-1]的右方,即x[i]-j>x[i-1]。顯然,如果青蛙能夠由x[i-1]-v位置跳至x[i]-j位置(can(x[i]-j-x[i-1]+v)=true),則跳至x[i]-j位置經過的石子總數為a[i-1,v]或者為a[i-1,v]+1(j=0時,即踩到了橋上的第i個石子)。但究竟v多大時,才能使得最少石子數最少呢,我們無法預知,只能在0‥t-1的範圍內一一枚舉v,從中找出經過的最少石子數。 最後,我們列舉青蛙跳出獨木橋前的最後乙個起跳位置x[n]-i(0≤i≤t-1),從中計算出青蛙過河最少需要踩到的石子數。
至於s=t的情況是不能用這種方法處理的,因此要特殊處理,模擬一遍就可以了。
【**】
view code
1var i,j,n,m,k,l,v:longint;
2 x:array[0..100]of longint;
3 a:array[0..100,0..100]of longint;
4 b:array[0..100]of boolean;
5 s,t,len:longint;
6function can(x:longint):boolean;
7begin
8if x<0
then exit(false);
9if x>=s*(s-1) then exit(true) else exit(b[x]);
10end;
11begin
12 assign(input,'
river.in
');reset(input);
13 assign(output,'
river.out
');rewrite(output);
14 readln(len);readln(s,t,n);
15for i:=1
to n do read(x[i]);
16for i:=1
to n do
17for j:=i+1
to n do
18if x[i]>x[j] then
19begin
20 k:=x[i];x[i]:=x[j];x[j]:=k;
21end;
22while x[n]>len do dec(n);
23 x[0]:=0;
24 fillchar(b,sizeof(b),false);
25 b[0]:=true;
26for i:=s to
90do
27for j:=s to t do
28 b[i]:=b[i]or b[i-j];
2930
if s=t then
31begin
32 k:=0;
33for i:=1
to n do
34if x[i]mod s=0
then inc(k);
35 write(k);
36 close(input);close(output);
37 halt;
38end;
3940 fillchar(a,sizeof(a),63);
41 a[0,0]:=0;
42for i:=1
to n do
43for j:=0
to t-1
do44
begin
45if x[i]-j<=x[i-1] then
46begin
47if a[i,j]>a[i-1,j-(x[i]-x[i-1])] then
48 a[i,j]:=a[i-1,j-(x[i]-x[i-1])];
49end
else
50begin
51for v:=0
to t-1
do52
if (can(x[i]-j-x[i-1]+v))and(a[i,j]>a[i-1,v]) then
53 a[i,j]:=a[i-1,v];
54if j=0
then inc(a[i,j]);
55end;
56end;
57 k:=maxlongint;
58for i:=0
to t-1
doif a[n,i]then k:=a[n,i];
59 writeln(k);
60 close(input);close(output);
61end.
NOIP2005 採藥 解題報告
輸入檔案 medic.in 輸出檔案 medic.out 簡單對比 時間限制 1 s 記憶體限制 128 mb 辰辰是個天資聰穎的孩子,他的夢想是成為世界上最偉大的醫師。為此,他想拜附近最有威望的醫師為師。醫師為了判斷他的資質,給他出了乙個難題。醫師把他帶到乙個到處都是草藥的山洞裡對他說 孩子,這個...
NOIP2005 過河題解
在河上有一座獨木橋,乙隻青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點 0,1,l 其中l是橋的長度 座標為0的點表示橋的起點,座標為l的點表示橋的終點。青蛙從橋的起...
noip2005提高組過河
介於被這道題折磨了一晚上,因此很有必要記錄下來做動態規劃及狀態壓縮中易錯事項。題目大意 共m個石子,求青蛙每次以s到t步從座標0跳過座標l踩到的最小石子數。樣例資料 輸入10 2 3 5 2 3 5 6 7 輸出資料範圍 1 l 10 9 1 s t 10,1 m 100 初看此題,可以想到動態規劃...