大致题意: 求出有多少个长度为(n)的排列满足对于奇数位(a_{i-1}<a_i),对于偶数位(a_{i-1}>a_i)。
考虑打表?
考虑每次只有一个数(n),且(nle1000),首先想到的自然是打表。
打表程序略(其实是手贱不小心删掉了)。
然后放到(OEIS)上,我们就可以找到一个(Python)的伪代码。
于是(hl666)神仙就切了此题。
动态规划
当然,像我这么弱,不会(Python),只好去写(DP)了。
我们可以设(f_i)表示有多少个长度为(i)的排列满足条件。
考虑加入一个数(i+1),我们可以把原来一个合法的数列挑选一个位置分成两半,枚举两边的数个数分别为(j)和(i-j)。
则两边的情况数其实分别就是(f_j)与(f_{i-j}),而(j)个数从(i)个数中的选择方案为(C_i^j)。
但问题在于这样刚好会有一半的情况是不合法的,因此还要再除以(2)。
所以最终的转移方程就是:
[f_{i+1}=frac{sum_{j=0}^if_jf_{i-j}C_i^j}2
]
也就相当于:
[f_i=frac{sum_{j=0}^{i-1}f_jf_{i-1-j}C_{i-1}^j}2
]
初始化(f_0=f_1=1)。
代码
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
#define N 1000
#define X 1000000007
#define C(x,y) (1LL*Fac[x]*Inv[y]%X*Inv[(x)-(y)]%X)
#define Qinv(x) Qpow(x,X-2)
#define Inc(x,y) ((x+=(y))>=X&&(x-=X))
using namespace std;
int n,a[N+5],f[N+5],Fac[N+5],Inv[N+5];
I int Qpow(RI x,RI y) {RI t=1;W(y) y&1&&(t=1LL*t*x%X),x=1LL*x*x%X,y>>=1;return t;}//快速幂
int main()
{
RI i,j,I2=X+1>>1;for(scanf("%d",&n),Fac[0]=i=1;i<=n;++i) Fac[i]=1LL*Fac[i-1]*i%X;//预处理阶乘
for(Inv[n]=Qinv(Fac[n]),i=n-1;~i;--i) Inv[i]=1LL*Inv[i+1]*(i+1)%X;//预处理阶乘逆元
for(f[0]=f[1]=1,i=2;i<=n;f[i]=1LL*f[i]*I2%X,++i) for(j=0;j^i;++j) Inc(f[i],1LL*f[j]*f[i-1-j]%X*C(i-1,j)%X);//DP转移
return printf("%d",f[n]),0;//输出答案
}