1. 程式人生 > >【BZOJ1925】[Sdoi2010]地精部落 組合數+DP

【BZOJ1925】[Sdoi2010]地精部落 組合數+DP

dash 高度 cst 分享 inpu zoj sample stream 個數

【BZOJ1925】[Sdoi2010]地精部落

Description

傳說很久以前,大地上居住著一種神秘的生物:地精。 地精喜歡住在連綿不絕的山脈中。具體地說,一座長度為 N 的山脈 H可分 為從左到右的 N 段,每段有一個獨一無二的高度 Hi,其中Hi是1到N 之間的正 整數。 如果一段山脈比所有與它相鄰的山脈都高,則這段山脈是一個山峰。位於邊 緣的山脈只有一段相鄰的山脈,其他都有兩段(即左邊和右邊)。 類似地,如果一段山脈比所有它相鄰的山脈都低,則這段山脈是一個山谷。 地精們有一個共同的愛好——飲酒,酒館可以設立在山谷之中。地精的酒館 不論白天黑夜總是人聲鼎沸,地精美酒的香味可以飄到方圓數裏的地方。 地精還是一種非常警覺的生物,他們在每座山峰上都可以設立瞭望臺,並輪 流擔當瞭望工作,以確保在第一時間得知外敵的入侵。 地精們希望這N 段山脈每段都可以修建瞭望臺或酒館的其中之一,只有滿足 這個條件的整座山脈才可能有地精居住。 現在你希望知道,長度為N 的可能有地精居住的山脈有多少種。兩座山脈A 和B不同當且僅當存在一個 i,使得 Ai≠Bi。由於這個數目可能很大,你只對它 除以P的余數感興趣。

Input

僅含一行,兩個正整數 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

題解:容易發現這是一個基於奇偶性的DP,那麽我們就分就來討論一下。

設f[i][0/1]表示有i段,其中最左邊那一段是山谷/山峰的方案數,那麽我們假設前i-1段已經放好了,現在我們枚舉第i段加入的位置,然後將左右兩邊的方案數乘起來,別忘了在乘上一個組合數。

還有這題P不是質數不能用逆元,只能n2求組合數,但是空間64MB開不下,所以要用滾動數組邊DP邊求組合數。

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
typedef long long ll;
int n;
ll f[4300][2],c[2][4300],mod;
int main()
{
	f[0][0]=f[0][1]=f[1][0]=c[1][0]=1;
	scanf("%d%lld",&n,&mod);
	int i,j;
	for(i=2;i<=n;i++)
	{
		c[i&1][0]=1;
		for(j=1;j<i;j++)	c[i&1][j]=(c[(i&1)^1][j-1]+c[(i&1)^1][j])%mod;
		for(j=0;j<i;j++)	(f[i][(j&1)^1]+=c[i&1][j]*f[j][(j&1)^1]%mod*f[i-j-1][0]%mod)%=mod;q
	}
	printf("%lld",(f[n][0]+f[n][1])%mod);
	return 0;
}

【BZOJ1925】[Sdoi2010]地精部落 組合數+DP