拯救LongMM (遞推公式求解)

2021-06-16 09:15:59 字數 3798 閱讀 6417

拯救l o n g m m ( l a n . p a s / c / c p p )

【題目描述】

longdd 將軍為了平息延續數年戰亂,決定釋放戰俘營中所有的俘虜。然而,

longdd 將軍不打算釋放敵軍的統帥longmm——因為這個傢伙異常聰明,是個難纏的

對手。所以longdd 將軍決定把longmm 用鍊子固定到牆上。鍊子由n 個環組成,每

個環有可能在牆上,也可能不在牆上。

「longdd 將軍,你為什麼把我綁在牆上,不讓我獲得自由」,longmm 咆哮道。

「但是,longmm,你並沒有被綁在牆上。我很確定你可以自己把鍊子解開」,

longdd 將軍回答道,「但是請你在天黑之前解開,否則我會因為你製造噪音把你重

新抓起來。」

請幫助longmm 吧!鍊子由n 個環組成,編號為1,2,…,n。我們可以把每個環從

牆上取下來或者從新放回牆上,但是需要遵循如下規則:

- 每一步只能取下或者裝上乙個環

- 編號為1 的環可以隨意取下或裝上

- 如果編號為1,…,k-1 的環都取下了,並且編號為k 的環在牆上,我們可

以隨意取下或者裝上第k+1 個環

- 當所有環都取下來之後,longmm 可以逃脫了

給定每個環的初始狀態,請你編寫程式計算longmm 最少需要多少步才能逃脫。

程式名: lan

【輸入格式】

* 第 1 行: 有乙個整數n,(1<=n<=1000),表示環的個數

* 第 2 行: 有n 個整數,第i 個整數o_i=0,表示第i 個環在初始的時候為摘下的

狀態;如果o_i=1,表示第i 個環初始的時候為裝在牆上的狀態。

【輸入樣例】

41 0 1 0

【輸出格式】

* 第 1 行: 只有乙個整數,表示最少需要多少步才能讓longmm 逃脫。

【輸出樣例】

6【輸出解釋】

先遞推 

然後 找規律 發現從後往前 ans=2^jn-2^j(n-1)+2^j(n-2)+.....   (j[i]表示從左往右第i個1)

program lan;

type

arr=record

len:longint;

d:array[1..1000] of longint;

end;

const

f=1000000;

var n,i:longint;

ans:arr;

p2:array[1..1000] of arr;

a:array[1..1001] of longint;

procedure multipy;

var i,j,k:longint;

begin

for k:=2 to 1000 do

begin

p2[k].len:=p2[k-1].len;

for i:=1 to p2[k-1].len do

begin

inc(p2[k].d[i],p2[k-1].d[i]*2);

inc(p2[k].d[i+1],p2[k].d[i] div f);

p2[k].d[i]:=p2[k].d[i] mod f;

end;

if p2[k].d[p2[k].len+1]<>0 then inc(p2[k].len);

end;

for k:=1 to 1000 do dec(p2[k].d[1]);

end;

function max(a,b:longint):longint;

begin

if a>b then exit(a) else exit(b);

end;

procedure add(a,b:arr;var c:arr);

var i,j:longint;

begin

fillchar(c,sizeof(c),0);

c.len:=max(a.len,b.len);

for i:=1 to c.len do

begin

inc(c.d[i],a.d[i]+b.d[i]);

inc(c.d[i+1],c.d[i] div f);

c.d[i]:=c.d[i] mod f;

end;

if c.d[c.len+1]>0 then inc(c.len);

end;

procedure sub(a,b:arr;var c:arr);

var i,j:longint;

begin

fillchar(c,sizeof(c),0);

c.len:=max(a.len,b.len);

for i:=1 to c.len do

begin

inc(c.d[i],a.d[i]-b.d[i]);

if c.d[i]<0 then

begin

inc(c.d[i],f);

dec(c.d[i+1],1);

end;

end;

while (c.len>1) and (c.d[c.len]=0) do dec(c.len);

end;

procedure work;

var i,j:longint;

flag:boolean;

begin

i:=n;

flag:=true;

while true do

begin

while (a[i]=0) and (i>1) do dec(i);

if a[i]=0 then exit;

if flag then add(ans,p2[i],ans)

else sub(ans,p2[i],ans);

dec(i);

if i=0 then exit;

flag:=not(flag);

end;

end;

procedure pri;

var i:longint;

begin

write(ans.d[ans.len]);

for i:=ans.len-1 downto 1 do

begin

if ans.d[i]<100000 then write('0');

if ans.d[i]<10000 then write('0');

if ans.d[i]<1000 then write('0');

if ans.d[i]<100 then write('0');

if ans.d[i]<10 then write('0');

write(ans.d[i]);

end;

writeln;

end;

begin

assign(input,'lan.in');

assign(output,'lan.out');

reset(input);

rewrite(output);

read(n);

for i:=1 to n do read(a[i]);

fillchar(ans,sizeof(ans),0);

fillchar(p2,sizeof(p2),0);

p2[1].len:=1;

p2[1].d[1]:=2;

multipy;

work;

pri;

close(input);

close(output);

end.

簡單遞推公式轉換矩陣求解

對於許多遞推題目,由於資料範圍太大直接迴圈寫會爆掉,這時首先想到的就是矩陣優化,把遞推式轉換成01矩陣通過快速冪優化。比如最簡單的斐波納挈,如果n非常大,迴圈遞推肯定是不合適的,那麼可以考慮下面的公式 f n f n 1 f n 1 f n 2 a 這裡的a是乙個01矩陣,此時的a 2 2的矩陣,可...

華為機試 放蘋果(遞推公式求解)

題目描述 把m個同樣的蘋果放在n個同樣的盤子裡,允許有的盤子空著不放,問共有多少種不同的分法?用k表示 5,1,1和1,5,1 是同一種分法。輸入每個用例包含二個整數m和n。0 m 10,1 n 10。樣例輸入 7 3樣例輸出 public static int count int m,int n ...

校內模擬 拯救(遞推)

這題年代可久遠了。似乎是今年寒假還是什麼時候loli的測試題來著?反正atp當時太水了不會做。現在越看越覺得當時很蛋疼 不過看這個題目的話,首先它的目標狀態是把所有的都變成0,所以會有乙個f i 表示把前i個都變成0所需要的最少步數 其次,它要改變第i個點的狀態一定是把前i 2個變成0並且把第i 1...