【线性DP】 杨老师的照相排列

提交点

点我查看题目

思路与反思

理解题意就理解了又蛮久,这方面还有待提高。
我首先是考虑了每个点放的位置,但是在他的排序的性质没有考虑完整,我是枚举每个位置的值,这个值受到左边和上边的影响,然后我就直接写动态方程了,都没有证明正确性!在代码实现的时候出现了一大波问题,导致直接WA。

动手之前一定要考虑自己思路的正确性,最好能够写出伪代码。

正确思路:
集合表示为每排已经排好位置(符合排列的规则)的所有方案。
属性为数量。

我们每次放值,只需要放到末尾就保证了集合中方案的正确性。

AC 代码

#include
using namespace std;

#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << ENDL
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;

const int N = 31;
ll f[N][N][N][N][N];

int main() {
#ifdef LOCAL
	freopen("data.in", "r", stdin);
#endif
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);

	int n;
	while (cin >> n && n) {
		int h[5] = {0};
		_for(i, 0, n) cin >> h[i];

		memset(f, 0, sizeof f);
		f[0][0][0][0][0] = 1;
		_rep(a, 0, h[0]) _rep(b, 0, min(a, h[1])) _rep(c, 0, min(b, h[2])) 
			_rep(d, 0, min(c, h[3])) _rep(e, 0, min(d, h[4])) {
			ll& v = f[a][b][c][d][e];
			if (a && a - 1 >= b) v += f[a - 1][b][c][d][e];
			if (b && b - 1 >= c) v += f[a][b - 1][c][d][e];
			if (c && c - 1 >= d) v += f[a][b][c - 1][d][e];
			if (d && d - 1 >= e) v += f[a][b][c][d - 1][e];
			if (e) v += f[a][b][c][d][e - 1];
		}
		cout << f[h[0]][h[1]][h[2]][h[3]][h[4]] << ENDL;
	}
	return 0;
}

你可能感兴趣的:(ACM)