NOIP2014 飛揚的小鳥 提高組

2022-03-17 18:03:14 字數 3766 閱讀 3842

題目:飛揚的小鳥

**:題目描述

玩家需要不斷控制點選手機螢幕的頻率來調節小鳥的飛行高度,讓小鳥順利通過畫面右方的管道縫隙。

如果小鳥一不小心撞到了水管或者掉在地上的話,便宣告失敗。

為了簡化問題,我們對遊戲規則進行了簡化和改編:

遊戲介面是乙個長為\(n\),高為\(m\)的二維平面,其中有\(k\)個管道(忽略管道的寬度)。

小鳥始終在遊戲介面內移動。小鳥從遊戲介面最左邊任意整數高度位置出發,到達遊戲介面最右邊時,遊戲完成。

小鳥每個單位時間沿橫座標方向右移的距離為\(1\),豎直移動的距離由玩家控制。如果點選螢幕,小鳥就會上公升一定高度\(x\),每個單位時間可以點選多次,效果疊加;如果不點選螢幕,小鳥就會下降一定高度\(y\)。小鳥位於橫座標方向不同位置時,上公升的高度\(x\)和下降的高度\(y\)可能互不相同。

小鳥高度等於\(0\)或者小鳥碰到管道時,遊戲失敗。小鳥高度為\(m\)時,無法再上公升。

現在,請你判斷是否可以完成遊戲。如果可以,輸出最少點選螢幕數;否則,輸出小鳥最多可以通過多少個管道縫隙。

輸入格式

第\(1\)行有\(3\)個整數\(n, m, k\),分別表示遊戲介面的長度,高度和水管的數量,每兩個整數之間用乙個空格隔開;

接下來的\(n\)行,每行\(2\)個用乙個空格隔開的整數\(x\)和\(y\),依次表示在橫座標位置\(0∼n−1\)上玩家點選螢幕後,小鳥在下一位置上公升的高度\(x\),以及在這個位置上玩家不點選螢幕時,小鳥在下一位置下降的高度\(y\)。

接下來\(k\)行,每行\(3\)個整數\(p,l,h\)每兩個整數之間用乙個空格隔開。每行表示乙個管道,其中\(p\)表示管道的橫座標,\(l\)表示此管道縫隙的下邊沿高度,\(h\)表示管道縫隙上邊沿的高度(輸入資料保證\(p\)各不相同,但不保證按照大小順序給出)。

輸出格式

共兩行。

第一行,包含乙個整數,如果可以成功完成遊戲,則輸出\(1\),否則輸出\(0\)。

第二行,包含乙個整數,如果第一行為\(1\),則輸出成功完成遊戲需要最少點選螢幕數,否則,輸出小鳥最多可以通過多少個管道縫隙。

資料範圍

\(5 ≤ n ≤ 10000,5 ≤ m ≤ 1000,0 ≤ k < n,0 < x, y < m,0 < p < n,0 ≤ l < h ≤ m,l+1 < h\)

輸入 #1

10 10 6 

3 9

9 9

1 2

1 3

1 2

1 1

2 1

2 1

1 6

2 2

1 2 7

5 1 5

6 3 5

7 5 8

8 7 9

9 1 3

輸出 #1
1

6

輸入 #2
10 10 4 

1 2

3 1

2 2

1 8

1 8

3 2

2 1

2 1

2 2

1 2

1 0 2

6 7 9

9 1 4

3 8 10

輸出 #2
0

3

說明/提示

如下圖所示,藍色直線表示小鳥的飛行軌跡,紅色直線表示管道。

揹包神題。經典的題目。

狀態轉移方程不難想:\(dp[i,j]=max(dp[i-1,j+y[i]], dp[i-1,j-k*x[i]]+k)\);代表小鳥當前處在橫座標為\(i\)縱座標為\(j\)位置上時的最小運算元。列舉\(k\)即可。

考慮到當小鳥飛到頂上的時候,不會死;因而\(dp[i,m]\)可能是由\(dp[i-1,1~m]\)轉移過來的。處理的時候單獨轉移。

其實能更好。考慮:當狀態\(dp[i,j]\)是由\(dp[i-1,j-2*x[i]]\)轉移過來,那麼假設\(dp[i,j-x[i]]\)是從\(dp[i-1,2*x[i]]\)轉移過來的,對\(dp[i,j]\)的求解其實可以通過dp[i,j-x[i]]$完成。

進一步,當\(dp[i,j]\)是從\(dp[i-1,j-k*x[i]]\)轉移而來,那麼,當考慮\(dp[i,j-x[i]]\)時也會從這裡轉移過來。該轉移等價於\(dp[i,j]\)從\(dp[i,j-x[i]]\)轉移過來。

由此,我們給出乙個新的方程式:\(dp[i,j]=max(dp[i-1,j+y[i]],dp[i,j-x[i]]+1)\),對於小鳥飛到頂上的情況,我們進行特殊運算時應當考察以下狀態:\(dp[i/(i-1),m-x[i]~m]\)即可求解。

事實上,上述的演算法還應當注意乙個細節。當我們將\(dp[i,j]\)用\(dp[i,j-x[i]]\)更新時,與此同時,\(dp[i,j-x[i]]\)又從\(dp[i-1,j-x[i]+y[i]]\)轉移過來,考慮它們本來的定義,會發現這樣的轉移是有毛病的。壓根不會存在同一位置小鳥先下降再上公升。

那麼,這可以通過求解的順序解決這種問題。具體細節看**。

**如下:

#include#include#include#includeusing namespace std;

const int maxn = 10000 + 5, maxm = 2000 + 5, inf = 1061109567;

int n, m, k, x[maxn], y[maxn], l[maxn], h[maxn], dp[maxn][maxm], s[maxn];

int main()

int l, h, p;

memset(s, 0, sizeof(s));

for(int i = 0; i < k; ++ i)

for(int i = 1; i <= n; ++ i) s[i] += s[i - 1];

memset(dp, 0x3f, sizeof(dp));

for(int i = 1; i <= m; ++ i) dp[0][i] = 0;//預處理的關鍵!!

for(int i = 1; i <= n; ++ i)

for(int j = m - x[i] + 1; j <= m; ++ j)//處理當小鳥飛到了頂上的狀態

for(int j = 1; j <= m - y[i]; ++ j)//後處理降落的情況

for(int j = 1; j < l[i]; ++ j) dp[i][j] = inf;//及時排除不合法的狀態

for(int j = h[i] + 1; j <= m; ++ j) dp[i][j] = inf;

} int ans = inf;

for(int i = 1; i <= m; ++ i)

if(ans < inf) printf("1\n%d\n", ans);

else

}if(valid) break;

} printf("0\n%d\n", s[i]);

} return 0;

}

NOIP2014 飛揚的小鳥

題目 分析 乙個揹包問題。i,j 是跳上來的情況時 可以由 i,j k 得到,則問題得到解決。注意 f陣列要先進行上公升操作,再進行下降操作,否則 i,j k 有可能是下降得到的,從而得到錯解 吸取我的教訓吧,調了好長時間 include include using namespace std co...

NOIP2014飛揚的小鳥

天哪細節問題調了乙個鐘,手速不夠快思路不夠清晰寫了乙個鐘,感覺一道第三題就要花掉我2個鐘那我比賽的時候腫麼辦qaq 說下這道題,首先純暴力,70分到手,然後我們把01揹包的轉移變成有上界的完全揹包,還有一些特殊情況特殊轉移,還是比較好看的,去年比賽不知是電腦問題還是什麼一直沒輸出,蠢到家了然後這題爆...

NOIP2014 飛揚的小鳥

傳送門 為了簡化問題,我們對遊戲規則進行了簡化和改編 1.遊戲介面是乙個長為n,高 為m的二維平面,其中有k個管道 忽略管道的寬度 2.小鳥始終在遊戲介面內移動。小鳥從遊戲介面最左邊任意整數高度位置出發,到達遊戲介面最右邊時,遊戲完成。3.小鳥每個單位時間沿橫座標方向右移的距離為1,豎直移動的距離由...