BZOJ 1925 地精部落 DP

2021-08-10 10:33:08 字數 1372 閱讀 6009

description

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

output

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

sample input

4 7

sample output

3 hint

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

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

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

對於 100%的資料,滿足 3≤n≤4200,p≤109

source

分析:本來想隨便水一道的,結果翻車了,想了好久。一開始想直接f[i][1/0]轉移的,0表示i點為峰,1表示為谷。後來想了想發現不對,這樣掃一遍過去只能得到一種合法的擺列,因為題目有說高度屬於1~n,於是行不通。現在考慮新的轉移,4200的範圍首先想到n^2,於是定義f[i][j],想想狀態,我們要求長度為n的波動序列的排列方案,則i肯定是表示前i位(一般套路),考慮j,首先給出下列3個公理:

1.不相鄰的x與x-1,交換位置後波動序列任然滿足(自己yy)。

2.把序列裡大於等於x的數加上任意數,序列任是波動。可以用一句話來「證明」,比你大還是比你大,你大爺還是你大爺。

3.對於乙個1~m的波動序列,一定可以對應得到n-m+1~n的波動序列。(只需要用n-m+1~n,和1~m,一一替換就ok了)

有了上面的buff,現在考慮dp,首先可以想到既然要算1~m的序列,則一定要表示出m,於是可以推出第二維為第乙個數大小用j表示。轉移方程為:f[i][j]=f[i][j-1]+f[i-1][i-j+1],f[i][j-1]對應定理2,若第二位不是j-1則可以交換j-1和j,等效。f[i-1][i-j]表示去掉j之後剩i-1個數,要保證加上j後原序列任然波動,則根據定理4,推出f[i-1][i-j]。最後加個滾動陣列優化一下就好。

# include 

# include

# include

# include

using

namespace

std;

typedef

long

long ll;

ll read()

c=getchar();}

while(c>='0'&&c<='9')

return i*f;

}const

int n=5000;

int n,p,ans,f[2][n],now=1;

int main()

f[1][1]=1;

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

printf("%d\n",(f[n&1][n]<<1)%p);

return

0;}

BZOJ 1925 地精部落 DP

其實不要小看一道地精部落,有比較大的思維量在裡面!我們首先知道 3 個性質 如果有想看證明的,請自動轉到 片下面,因為考慮有些人不想看證明 fi rst fir st 對於每乙個 數字 i 和 i 1 如果這兩個數不是相鄰的,那麼交換兩個數字的對應的方案數是一樣的!比如有 波動序列 32 415 3...

BZOJ1925 地精部落

題目描述 輸入格式 僅含一行,兩個正整數 n,p。輸出格式 僅含一行,乙個非負整數,表示你所求的答案對p取餘之後的結果。樣例樣例輸入 4 7樣例輸出 3資料範圍與提示 對於 20 的資料,滿足 n 10 對於 40 的資料,滿足 n 18 對於 70 的資料,滿足 n 550 對於 100 的資料,...

BZOJ 1925地精部落題解

題目鏈結 一道神仙題,有很多思考的方式,這裡選擇最好理解的一種來講 我們將序列分為兩種,一種開頭遞增,一種開頭遞減,顯然這兩種序列的數目是一樣的 現在我們只用考慮開頭遞增的情況 f i j 表示前i個數,最後乙個數字在前i個數的排名在1 j之間的方案數 顯然有f i j f i j 1 如果最後乙個...