P2467 [SDOI2010] 地精部落

Captain_Paul

2018-05-15 14:41:57

Personal

dp求方案数的问题 用f[i]表示长度为i的第一位为山峰的波动山脉数量 显然第一位是山谷和山峰的数量是一样的 所以最终答案为f[n]*2 可以以最大数的位置为分界点,把长度为n的序列分成两份 当最大数在奇数位时,第一个一定是山峰 当最大数在偶数位时,第一个一定是山谷 所以通过枚举最大数的位置进行状态转移 把两段的方案数相乘再乘以组合数,求出总和即为f[i] ~~好像可以用滚动数组优化然而我不会~~ ``` #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N=4205; int n,p,f[N],c[N][N]; inline void calc() { c[0][0]=1; for (int i=1;i<=n;i++) { c[i][0]=1; for (int j=1;j<=i;j++) c[i][j]=(c[i-1][j]+c[i-1][j-1])%p; } } int main() { scanf("%d%d",&n,&p); f[0]=f[1]=1; calc(); for (int i=2;i<=n;i++) for (int j=1;j<i;j+=2)//枚举最大数位置 f[i]=(f[i]+(ll)f[j]*c[i-1][j]%p*f[i-j-1])%p; printf("%d\n",f[n]*2%p); return 0; } ```