题目链接:http://www.lightoj.com/volume_showproblem.php?problem=1173
题解:像这种题目显然可以想到n为几时一共有几种排列可以递推出来。然后就是对m的考虑如果m只能在第一位那么显然需要的组合是先下降后上升的如果m不在第一位那么需要的组合是先上升后下降的。于是便可以想到设dp_in[i][j]表示i个数第j个数放在第一个而且是先上升后下降的一共有几种方法,dp_de[i][j]表示i个数第j个数放在第一个而且是先下降后上升的有几种方法。
dp_in[i][j]=sum(dp_de[i-1][j])(i<=j<n)
dp_de[i][j]=sum(dp_in[i-1][j])(1<=j<i)
#include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef unsigned long long ll; ll dp_in[55][55] , dp_de[55][55]; void init() { memset(dp_in , 0 , sizeof(dp_in)); memset(dp_de , 0 , sizeof(dp_de)); dp_in[1][1] = 1 , dp_de[1][1] = 1; for(int i = 2 ; i <= 50 ; i++) { for(int j = 1 ; j <= i ; j++) { for(int l = 1 ; l < j ; l++) { dp_de[i][j] += dp_in[i - 1][l]; } for(int l = j ; l < i ; l++) { dp_in[i][j] += dp_de[i - 1][l]; } } } } int main() { int t , Case = 0 , n , m; scanf("%d" , &t); init(); while(t--) { scanf("%d%d" , &n , &m); ll ans = 0; if(m == 1) { if(n <= 2) ans += 1; else ans += dp_de[n - 1][2]; } else { for(int i = 1 ; i < m ; i++) { ans += dp_in[n - 1][i]; } } printf("Case %d: %llu\n" , ++Case , ans); } return 0; }