地精部落 題解

2022-03-26 20:36:07 字數 1372 閱讀 5904

題目描述

輸入格式

僅含一行,兩個正整數 n, p。

輸出格式

僅含一行,乙個非負整數,表示你所求的答案對p取餘 之後的結果。

樣例樣例輸入

4 7
樣例輸出

3
資料範圍與提示

對於 20%的資料,滿足 n≤10;

對於 40%的資料,滿足 n≤18;

對於 70%的資料,滿足 n≤550;

對於 100%的資料,滿足 3≤n≤4200,p≤10910^910​9​​

一看似乎不太好轉移,每個數要比它兩邊的數大或小,如果直接針對每個數進行狀態轉移,不太好弄

然而我們研究一下這種序列,要按照 小 大 小...這樣,那麼如果我們在一整個序列前加乙個更大的數,變成 大 小 大 小 有成乙個合法序列了

乙個大小大小的序列可以唯一對應乙個小大小大的合法序列,比如213變為231,相當於每個數a變為n-a+1,所以小大小大的個數與大小大小的個數相同

用f[i][j]表示長度為i的序列,開頭為j的方案數 並且是大小大小

怎麼轉移?

再看看另乙個特性

對於序列中的x和x+1,只要他們不相鄰,交換後得到乙個新序列仍合法。畫一張圖比較好得出

那麼我們可以利用這一點直接從f[i][j-1]轉移到f[i][j]

長為i,第乙個數為j-1,它的第二個數一定小於j-1,也就是j一定不與j-1相鄰,那麼j與j-1交換就可以得到長為i第一位j,第二位不是j-1(比j-1小)的合法序列

要得到第二位是j-1的序列,可以將長為i-1的狀態轉移過來

找長i-1的首位是j-1 並且是 小 大 小 大 的序列,這樣直接在前面添上j就合法了

那麼這樣的序列個數其實就是長為j-1首位為(i-1)-(j-1)的序列的個數(相當與用i-1去減沒乙個數,變成小大小大)

合起來f[i][j]=f[i][j-1]+f[i-1][(i-1)-(j-1)+1]

1 #include2 #include3 #include4

using

namespace

std;

5intn;6

intp;

7int f[4300][4300];8

intmain()17}

18int ans=0;19

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

20 ans=1ll*(ans+f[n][i])%p;

21 ans=2ll*ans%p;

22 printf("

%d\n

",ans);

23 }

view code

題解 地精部落 DP

設 f i 表示強制第乙個是谷的合法方案數 轉移列舉乙個排列的最大值在 就把序列分成了互不相干的兩個部分,把其中 i 1 choose j 1 的數字分配給前面部分,剩下的給後面。轉移從所有可以轉移的偶數過來 winlere include include include includeusing ...

地精部落 dp

description input 僅含一行,兩個正整數 n,p。output 僅含一行,乙個非負整數,表示你所求的答案對p取餘 之後的結果。sample input 4 7sample output 3hint 對於 20 的資料,滿足 n 10 對於 40 的資料,滿足 n 18 對於 70 的...

BZOJ 地精部落

僅含一行,兩個正整數 n,p。僅含一行,乙個非負整數,表示你所求的答案對 p 取餘 之後的結果。input 4 7output 3對於 20 的資料,滿足 n 10 對於 40 的資料,滿足 n 18 對於 70 的資料,滿足 n 550 對於 100 的資料,滿足 3 n 4200,p 10 9 ...