题意:给出一个n,然后使用1-n构造出波浪形数据,问能构造多少组?
题解:很难想到,首先考虑从小到大进行插队,当插入最后这个最大的数时,怎么能插入进入呢?除非这个数前面是高低,后面是低高的形式,那么就用dp[i][0]表示符合波浪形且最后是高低的形式,用dp[i][1]表示符合波浪形开头是低高的形式,然后我们就开始从i-1个人中选出j个人去当这个dp[j][0],选法一共有c[i-1][j]种,这种组合数可以采用数组递推的形式出来, 参考传送门,之后就可以写出递推方程式了,此时的总方案数是ans=dp[j][0]*dp[i-j-1]*c[i-1][j],(0<=j<=i-1)之后还得考虑dp[i][0]与dp[i][1]怎么办?是否平分这个ans,答案是是的,当i是偶数时,最后两个是高低和开头两个是低高正好平分总方案数,当i是奇数时,最后两个是高低和开头两个是低高也正好平分总方案数,最后输出时将1特判下即可。
附上代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=20+5;
ll dp[maxn][2],c[maxn][maxn];
void getc()
{
for(int i=0;i<maxn;i++){
c[i][0]=c[i][i]=1;
}
for(int i=2;i<maxn;i++){
for(int j=1;j<i;j++){
c[i][j]=c[i-1][j-1]+c[i-1][j];
}
}
}
void mt()
{
dp[0][0]=dp[0][1]=dp[1][0]=dp[1][1]=1;
for(int i=2;i<maxn;i++){
ll ans=0;
for(int j=0;j<i;j++){
ans+=dp[j][0]*dp[i-j-1][1]*c[i-1][j];
}
dp[i][0]=dp[i][1]=ans/2;
}
}
int main()
{
getc();
mt();
int p;
scanf("%d",&p);
while(p--){
int id,n;
scanf("%d%d",&id,&n);
if(n==1){
printf("%d %d\n",id,1);
}else{
printf("%d %lld\n",id,dp[n][0]+dp[n][1]);
}
}
return 0;
}