题意不说,直接上思路:
这道题看起来没有思路,不清楚如何安排能够保证左边l根,右边r根,所以需要简化这道题,让思路浮现出来,
我们摆放顺序不能是从左到右或者从右到左的顺序摆放,而从小到大不行,所以是从大到小可以,原因是摆放小的不会影响大的,
将小的摆放左边一定能够使左边+1,同理右边也是一样,而中间则不能对左右造成影响,而从小到大的顺序会对左右产生影响,
并且不能够很清楚的知道影响了多少(想一想,为什么)。
所以根据上面定义了状态d(i,j,k)表示从大到小前i个,左边为j,右边为k的方案数,不难想出状态方程:
放在左边:d(i,j,k) += d(i-1,j-1,k)
右边: d(i,j,k) += d(i-1,j,k-1)
中间: d(i,j,k) += d(i-1,j,k)*(i-2)
所以总的转移方程为: d(i,j,k) = d(i-1,j-1,k) + d(i-1,j,k-1) + d(i-1,j,k)*(i-2)
代码如下:
// UVa 1638 #include <cstdio> #include <cstring> using namespace std; const int maxn = 20; long long d[maxn+1][maxn+1][maxn+1]; void init() { memset(d, 0, sizeof(d)); d[1][1][1] = 1; for (int i = 2; i <= maxn; ++i) for (int j = 1; j <= i; ++j) for (int k = 1; k <= i; ++k) { d[i][j][k] = d[i-1][j][k] * (i - 2); if (j > 1) d[i][j][k] += d[i-1][j-1][k]; if (k > 1) d[i][j][k] += d[i-1][j][k-1]; } } int main() { init(); int T, n, l, r; scanf("%d", &T); while (T--) { scanf("%d%d%d", &n, &l, &r); printf("%lld\n", d[n][l][r]); } return 0; }
原文地址:https://www.cnblogs.com/yifeiWa/p/11412164.html
时间: 2024-10-05 05:49:58