Catalog
题解 SP15637 【GNYR04H - Mr Youngs Picture Permutations】

查看原题请戳这里

一道五维DP的题目

首先,我们发现,当我们排完部分队形时,已经排好的队形对后续的方案数是有影响的,显然我们这样DP是非常困难的。所以,我们可以选择安装身高顺序插入,每次的决策是第i个人插入的位置。

我们可以发现,如果我们要向第i行的末尾插入一个人,那么第i行的状态必须满足以下两个条件:

  1. $l_i<k_i$

  2. $l_i<l_i-1 \ || \ i = 1 $

第一个条件是保证第i行的人数不会超出上限,第二个条件用来保证列与列直接的单调性。

对于数组的大小,我们发现开$30^5$其实是一个非常大的级别。于是,我们可以这样开:

1
long long f[31][16][11][9][7];

解释一下:

因为第i行的人数一定小于等于第i - 1行的人数,所以第i行最多放$30 / i$个人。

code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#define ll long long
#define INF 0x7fffffff
#define re register
#define rep(i,a,b) for(int i = (a); i <= (b); i++)
#define qwq printf("qwq\n");

using namespace std;

int read()
{
register int x = 0,f = 1;register char ch;
ch = getchar();
while(ch > '9' || ch < '0'){if(ch == '-') f = -f;ch = getchar();}
while(ch <= '9' && ch >= '0'){x = x * 10 + ch - 48;ch = getchar();}
return x * f;
}

long long f[31][16][11][9][7],n,k[100005];

int main()
{
while(1)
{
n = read();
if(!n) break;
memset(k,0,sizeof(k));
memset(f,0,sizeof(f));
f[0][0][0][0][0] = 1;
for(int i = 1; i <= n; i++) k[i] = read();
for(int a = 0; a <= k[1]; a++)
for(int b = 0; b <= k[2]; b++)
for(int c = 0; c <= k[3]; c++)
for(int d = 0; d <= k[4]; d++)
for(int e = 0; e <= k[5]; e++)
{
if(a < k[1])f[a + 1][b][c][d][e] += f[a][b][c][d][e];
if(b < a && b < k[2])f[a][b + 1][c][d][e] += f[a][b][c][d][e];
if(c < b && c < k[3])f[a][b][c + 1][d][e] += f[a][b][c][d][e];
if(d < c && d < k[4])f[a][b][c][d + 1][e] += f[a][b][c][d][e];
if(e < d && e < k[5])f[a][b][c][d][e + 1] += f[a][b][c][d][e];
}
printf("%lld\n",f[k[1]][k[2]][k[3]][k[4]][k[5]]);
}
return 0;
}
Author: wflight
Link: http://yoursite.com/2019/09/19/题解-SP15637-【GNYR04H-Mr-Youngs-Picture-Permutations】/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
  • 支付寶

Comment