CSAPC08台灣邀請賽 T1 skyline

2022-05-12 14:29:21 字數 2411 閱讀 9031

一座山的山稜線由許多片段的45度斜坡構成,每乙個片段不是上坡就是下坡。

/ *

/​ * * /

​/ * /\ //

​/ // /

在我們眼前的所見的任何寬度為n個單位的山稜形狀,可以輕鬆地觀察到所有山頂的位置。

請問有多少種山稜線的形狀,使得所有山頂的位置由左而右非遞減呢?

所有的山稜線都必須完整,也就是說左右兩端都必須是高度為0的山腳,而且不能有任何山谷的位置隱沒在地平線底下。

輸入僅包含乙個數字n,n一定會是偶數,因為會有相同片段數量的上坡以及下坡。

請輸出山頂位置由左而右非遞減的山稜線形狀總數。

由於答案可能很大,你只要輸出以十進位表示時,它的最後9位數即可。

佔總分20%的測試資料中 n<=60

佔總分40%的測試資料中 n<=200

佔總分100%的測試資料中 n<=3000

這題考場上耗了我大半的時間還沒搞出來qwq。

首先,根據題意分析,很容易就能看出這是個區間dp。

區間dp怎麼傳遞呢?看到題目要求:求寬度為\(n\),山頂高度非降的方案和。所以我們可以開乙個二維陣列\(dp[i][j]\)記錄答案:第一維\(i\)用來記錄限定條件:「寬度」;第二維\(j\)來記錄限定條件:這些山峰的最高高度\(j\),以便轉移。

但是啊,我們的\(dp\)陣列只能記錄最高高度為\(j\)的情況,那如果我要拓寬寬度的話,肯定是不能再把所有的最高高度的情況又重新列舉累加的,所以考慮用乙個字首和陣列\(sum[i][j]\)來記錄寬度為\(i\),最高高度限定為\(j\)(可以小於\(j\))的所有情況,可以說\(sum\)陣列就是把寬度為\(i\)的所有合法情況記錄了下來。

接下來就是轉移了。

首先我們有兩大種情況:

ⅰ.我們的\(dp[i][j]\)的情況可以直接由\(dp[i-1][j-1]\)的情況得到;

這就相當於可以想象把\(dp[i-1][j-1]\)中包含的山的情況整體往上拱了一層。如下圖:

ⅱ.我們也可以通過在\(sum[i-2][j]\)的基礎上加上一座最小的山。如下圖:

因為\(sum[i-2][j]\)加上一座單位高度的小山已經把類似於最低山的高度大於單位長度的所有情況考慮了進來,而我們的情況ⅰ就是對應著這種「最低山的高度大於單位長度」的所有情況。

所以任何情況已經可以用以上兩種情況相互疊加著表示,可以保證的是這麼算目前已經沒有遺漏了。

但其實還會存在乙個小問題。

在整體寬度為\(i+j\)時,假設我們的右邊有一座高度為\(j\)的山峰,那麼顯然地,這座山峰的寬度為\(2j\),所以去掉右邊的山峰後,我們左邊部分的山峰寬度為\(i-j\),那麼我們的\(sum[i-2j][j]\)就可以表示當前說的這種情況的所有方案,此時是合法的。

不過我們若將左邊部分的寬度減少乙個單位勻給右邊部分,右邊部分一定不能在保持只有一座山峰的情況下保證最高高度為\(j\),所以不合法。

但是可能會有點想不通的是:為什麼右邊就一定只能有一座山峰呢?

其實,注意一下我們的轉移方程,我們的\(sum[i-2][j]\)是通過和乙個單位高度的山峰組合在一起作為答案加進我們的\(dp\)陣列裡去的,然後當我們的單位高度小山峰被墊高到了高度\(j\)時,與它同組搭配的\(sum\)陣列的組合情況就必須考慮一下其合法性了,因為這種非法組合也本來就不能算在答案裡。於是考慮刪除。

**就在下面,這篇題解其實更多就是對下面的**的解釋因為這個標程一點注釋都沒有啊。

#include #include #include #include using namespace std;

const int n=3010;

const int p=1000000000;

int n,dp[n][n],sum[n][n];

int main()

}sum[i][j]=(sum[i-1][j]+dp[i][j])%p;

} dp[i][i]=1;sum[i][i]=1;

} while (scanf("%d",&n)!=eof)

printf("%d\n",ans);

} return 0;

}

字元0 數字0和 0

binoct dechex 縮寫 字元 解釋0000 000000 00nut null 空字元00110000 6048300 字元0ascii碼值 0 表示空字元,空字元就是平時所說的 0 字元 0 ascii碼值為 48,如 012 字串中的 0 表示字元 0 數字 0,所說的數字 0,就是平...

C語言 0 和0和 0

共同點 都是字元 不同點 0 對應的ascii碼是0,是ascii碼表中的第乙個字元,即空字元 判斷乙個字串是否結束的標誌就是看是否遇到 0 0 對應的ascii碼是48,48對應的十六進製制數就是0x30。0 是字串常量,字串常量是由一對雙引號括起的字串行。字串常量可以含乙個或多個字元。0 是字元...

徹底搞定0x0d和0x0a

我只在arm linux c和vc 下做了試驗,請大家在接觸其它語言環境下,小心推廣,不行就自己動手做試驗,最可靠。在arm linux c和vc 下回車換行的意義如下。回車 cr ascii碼 r 十六進製制,0x0d,回車的作用只是移動游標至該行的起始位置 換行 lf ascii碼 n 十六進製...