POJ 2279 Mr. Young‘s Picture Permutations【线性DP】

题目链接

题目描述

标号为 1 ~ N 的同学站成 k 行,每行人数为 a i a_i ai,规则入下图所示,同一行标号从左向右递增,同一列标号从后向前递减,前面的列数不长于后面的列数,问方案有多少种。在这里插入图片描述


题解:

  1. 满足两个方向的递增:因为在合法的方案中,每行每列都是递增的,所以我们可以考虑从标号 1 到 N 开始放,对于同一行的递增,后放的一定大,满足了从左到右递增;对于同一列的递增,后放的也一定大(要满足这一列的行是最后一行或者要放的这一行同一列后面的行已经放了数),这满足了从后向前递增。
  2. 满足前面行数不大于后面行数,所以要满足两个条件:在放的时候(1)考虑行:令 n o w i now_i nowi 表示当前第 i 行放的个数,要满足 n o w i < a i now_i<a_i nowi<ai;(2)考虑列:这一列是最后一列 i = 1 i = 1 i=1 或者 n o w i − 1 > n o w i now_{i - 1} > now_i nowi1>nowi
  3. 状态转移方程详细见代码。

AC Codes:

#include <iostream>
#include <vector>
#include <queue>
#include <stack>
#include <set>
#include <map>
//#include <unordered_set>
//#include <unordered_map>
#include <deque>
#include <list>
#include <iomanip>
#include <algorithm>
#include <fstream>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <cstdlib>
//#pragma GCC optimize(2)
using namespace std;
typedef long long ll;
//cout << fixed << setprecision(2);
//cout << setw(2);
const int N = 31, M = 1e9 + 7, INF = 0x3f3f3f3f;

unsigned int dp[N][N][N][N][N];

int main() {
    //freopen("/Users/xumingfei/Desktop/ACM/test.txt", "r", stdin);
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int k;
    while (cin >> k && k) {
        vector<int> a(6, 0);
        for (int i = 1; i <= k; i++) cin >> a[i];
        for (int i = 0; i <= a[1]; i++) 
            for (int j = 0; j <= a[2]; j++) 
                for (int k = 0; k <= a[3]; k++) 
                    for (int x = 0; x <= a[4]; x++) 
                        for (int y = 0; y <= a[5]; y++)
                            dp[i][j][k][x][y] = 0;
        dp[0][0][0][0][0] = 1;
        for (int i = 0; i <= a[1]; i++) 
            for (int j = 0; j <= a[2]; j++) 
                for (int k = 0; k <= a[3]; k++) 
                    for (int x = 0; x <= a[4]; x++) 
                        for (int y = 0; y <= a[5]; y++) {
                            if (i < a[1]) dp[i + 1][j][k][x][y] += dp[i][j][k][x][y];
                            if (j < a[2] && j < i) dp[i][j + 1][k][x][y] += dp[i][j][k][x][y];
                            if (k < a[3] && k < j) dp[i][j][k + 1][x][y] += dp[i][j][k][x][y];
                            if (x < a[4] && x < k) dp[i][j][k][x + 1][y] += dp[i][j][k][x][y];
                            if (y < a[5] && y < x) dp[i][j][k][x][y + 1] += dp[i][j][k][x][y];
                        }
        cout << dp[a[1]][a[2]][a[3]][a[4]][a[5]] << '\n';
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值