1. 程式人生 > >bzoj 1925 地精部落

bzoj 1925 地精部落

Written with StackEdit.

Description

傳說很久以前,大地上居住著一種神祕的生物:地精。 地精喜歡住在連綿不絕的山脈中。具體地說,一座長度為 \(N\) 的山脈 \(H\)可分 為從左到右的\(N\) 段,每段有一個獨一無二的高度 \(H_i\),其中\(H_i\)\(1\)\(N\) 之間的正 整數。 如果一段山脈比所有與它相鄰的山脈都高,則這段山脈是一個山峰。位於邊 緣的山脈只有一段相鄰的山脈,其他都有兩段(即左邊和右邊)。 類似地,如果一段山脈比所有它相鄰的山脈都低,則這段山脈是一個山谷。 地精們有一個共同的愛好——飲酒,酒館可以設立在山谷之中。地精的酒館 不論白天黑夜總是人聲鼎沸,地精美酒的香味可以飄到方圓數裡的地方。 地精還是一種非常警覺的生物,他們在每座山峰上都可以設立瞭望臺,並輪 流擔當瞭望工作,以確保在第一時間得知外敵的入侵。 地精們希望這\(N\)

段山脈每段都可以修建瞭望臺或酒館的其中之一,只有滿足 這個條件的整座山脈才可能有地精居住。 現在你希望知道,長度為\(N\) 的可能有地精居住的山脈有多少種。兩座山脈\(A\)\(B\)不同當且僅當存在一個 \(i\),使得 \(A_i≠B_i\)。由於這個數目可能很大,你只對它除以\(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≤10^9.\)

Solution

  • 題面廢話很多,就是求長度為\(N\)的波動序列的個數.
  • 注意到對於任意一個波動序列\(a\),將其中的每個\(a_i\)變為\(N+1-a_i\),仍是一個波動序列,且由先升後降變為先降後升,或由先降後升變為先升降.
  • eg.\(1,3,2,4\)->\(4,2,3,1\).
  • 那麼我們只需要求出先降後升的序列個數,再乘\(2\)即為答案.
  • 考慮令\(f[i]\)表示\(i\)
    個不同的陣列成的先降後升的序列個數.(不同即可,與具體大小無關)
  • 計算\(f[i]\)時,考慮列舉最大的數所在的位置\(j\),顯然是一個奇數.
  • 那麼它前面還有\(j-1\)個數,後面還有\(i-j\)個數.
  • 我們從剩餘的\(i-1\)個數中選出\(j-1\)個數放在前面,剩餘的放在後面.
  • 有轉移方程\(f[i]=\sum_{j=2k+1,k\in N}^{i} C_{i-1}^{j-1}*f[j-1]*f[i-j]\).
  • 時間複雜度為\(O(n^2)\).
  • 由於\(P\)是讀入的,組合數的計算使用遞推.但直接開\(n^2\)的陣列會\(MLE\),需要滾動陣列計算(第一次見到組合數還要滾動陣列的).
#include<bits/stdc++.h>
using namespace std;
typedef long long LoveLive;
inline int read()
{
    int out=0,fh=1;
    char jp=getchar();
    while ((jp>'9'||jp<'0')&&jp!='-')
        jp=getchar();
    if (jp=='-')
        {
            fh=-1;
            jp=getchar();
        }
    while (jp>='0'&&jp<='9')
        {
            out=out*10+jp-'0';
            jp=getchar();
        }
    return out*fh;
}
int n,P;
inline int add(int a,int b)
{
    return (a + b) % P;
}
inline int mul(int a,int b)
{
    return 1LL * a * b % P;
}
int fpow(int a,int b)
{
    int res=1;
    while(b)
        {
            if(b&1)
                res=mul(res,a);
            b>>=1;
            a=mul(a,a);
        }
    return res;
}
const int MAXN=4396;
int f[MAXN];
int C[2][MAXN];
int main()
{
    n=read(),P=read();
    f[0]=1;
    int id=1;
    for(int i=1;i<=n;++i)
        {
            C[id^1][0]=1;
            C[id][0]=1;
            for(int j=1;j<=i;++j)
                {
                    C[id][j]=add(C[id^1][j],C[id^1][j-1]);
                    if(j&1)
                        f[i]=add(f[i],mul(C[id^1][j-1],mul(f[j-1],f[i-j])));
                }
            id^=1;
        }
    int ans=mul(f[n],2);
    printf("%d\n",ans);
    return 0;
}