这周的专题是回溯,而我这题的解法是排列组合,思路其实是DP的思维,考虑到N个人的排列中最高的那个人可能站的位置,把整个排列分成两个部分,要使整个排列从前往后看是p个人,递归的解决前半部分从前往后看是p-1个人的子问题,问题存在最优子结构和重复计算的性质,肯定可以用动态规划自底向上解决,考虑到数据的范围较小,所以用递归没有问题。特别要注意的是这里的前半部分要用有C(n-1,i)种选择,对于后半部分可以任意组合所以有A(n-i-1)种组合,特别懵逼的是自己做的D题,一个劲的交C题,然后拼命找WA的原因的状态,真的…一言难尽!
/*代码没注释,回看两行泪*/
LL A(LL n){
if(n<=1)
return 1;
return n*A(n-1);
}
LL C(LL m,LL n){
return A(m)/A(n)/A(m-n);
}
//解决n个位置,从前往后或从后往前看 能看到p个人的子问题
//从后往前看和从前往后是对称的
LL solve(LL n,LL p){
if(n<p) return 0;//不可能
if(n==p) return 1;
LL ans=0;
for(int i=0;i<n;i++){//i代表把最高的人置于这个位置
ans+=C(n-1,i)*solve(i,p-1)*A(n-i-1);
}
return ans;
}
int main()
{
int t;cin>>t;
while(t--){
int n,p,r;
cin>>n>>p>>r;
LL ans=0;
for(int i=0;i<n;i++){//i代表把最高的人置于这个位置
ans+=C(n-1,i)*solve(i,p-1)*solve(n-i-1,r-1);
}
cout<<ans<<endl;
}
return 0;
}