题解 P2467 【[SDOI2010]地精部落】

devout

2020-11-25 11:44:45

Solution

**description** 求长度为 $n$ 的每个位置都是极值的排列的个数对 $p$ 取模的结果。 $n\leq 4200$ **solution** 我们观察发现,对于一个最开始是极大值的满足条件的序列,如果把整个序列翻过来,即 $a_i=n+1-a_i$ 时,一定也是可以的。 所以我们只需要求第一个位置为极大值的序列个数。 设 $f_i$ 表示一个 $1$ 到 $i$ 的排列,第一个位置为极大值的方案数。 考虑将这些数从小到大放进去,考虑到 $i$ 时,设他排在第 $j$ 个位置,那么可以得到转移 $$f_i=\sum_{j=1,j\bmod 2=1}^i f_{j-1}\times f_{i-j}\times\binom{i-1}{j-1}$$ 这样的转移就是 $O(n^2)$ 的了,只需要最后 $\times 2$ 就可以了 **code** ```cpp # include <bits/stdc++.h> using namespace std; # define Rep(i,a,b) for(register int i=a;i<=b;i++) # define _Rep(i,a,b) for(register int i=a;i>=b;i--) # define RepG(i,u) for(int i=head[u];~i;i=e[i].next) typedef long long ll; const int N=4205; template<typename T> void read(T &x){ x=0;int f=1; char c=getchar(); for(;!isdigit(c);c=getchar())if(c=='-')f=-1; for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0'; x*=f; } int n,m; int f[N]; int C[2][N]; int main() { read(n),read(m); f[0]=1; C[0][0]=C[1][0]=1; Rep(i,1,n){ Rep(j,1,i) if(j&1)(f[i]+=1ll*f[j-1]*f[i-j]%m*C[i&1^1][j-1]%m)%=m; Rep(j,1,i)C[i&1][j]=(C[i&1^1][j]+C[i&1^1][j-1])%m; C[i&1][0]=1; } printf("%d\n",2*f[n]%m); return 0; } ```