noip2005 過河 解題報告

2022-08-15 01:39:13 字數 3483 閱讀 8553

過河 解題報告

【問題描述】

在河上有一座獨木橋,乙隻青蛙想沿著獨木橋從河的一側跳到另一側。在橋上有一些石子,青蛙很討厭踩在這些石子上。由於橋的長度和青蛙一次跳過的距離都是正整數,我們可以把獨木橋上青蛙可能到達的點看成數軸上的一串整點: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

1

var 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 初看此題,可以想到動態規劃...