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 如果最後乙個...