abcdeffa's Blog

当局者迷,旁观者清。

0%

GMOJ S3712 【石中剑的考验】

Description

给出一个 $1$ ~ $n$ 的排列的最长上升子序列的长度 $k$ 以及这个序列,请你求出原排列可能的种类数,数据保证答案小于 $2^{31}$ 。

Solution

考虑使用 状压 DP 来解题。

考虑原排列在什么情况下合法,发现原排列合法的充要条件是 给出的子序列是原排列的子序列 以及 原排列的最长上升子序列长度为 $k$

发现如果记录下当前所选状态的最长上升子序列的话不行,于是可以联想到 $O(n \log n)$ 求最长上升子序列的方法,记录下每个数是否在求最长上升子序列的队列中即可。

于是我们可以设 $f[S]$ 表示当前选的数的状态为 $S$ 的方案数。

其中 $S$ 为一个三进制数,第 $i$ 位为 0 表示该数未选,第 $i$ 位为 1 表示该数选了并且在队列中,第 $i$ 位为 2 表示该数选了但是不在队列中。

然后就可以转移了。

注意如果是用 DP 来转移的话不能将 1 和 2 的定义调换,因为这样可能会由一个较大的状态转移到一个较小的状态去,造成答案错误。

当然如果要调换 1 和 2 的定义的话也可以用 BFS 来进行转移,交由读者练习。

注意三进制状态与二进制状态在转移上的区别,在本题中不要乱用 &|^ 等符号。

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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
#include <cstdio>
#define maxN 15
#define maxM 15
int f[14348917], a[maxN + 1], b[maxM + 1], c[maxM + 1];
int pow[maxM + 1], bj[maxM + 1];
int main ()
{
pow[0] = 1;
for(int i = 1;i <= maxM; i++)
{
pow[i] = pow[i - 1] * 3;
}
int ans = 0, m = 0, n = 0;
scanf("%d %d", &m, &n);
for(int i = 1;i <= n; i++)
{
scanf("%d", &a[i]);
bj[a[i]] = i;
}
int ma = pow[m] - 1;
f[0] = 1;
for(int S = 0;S <= ma; S++)
{
if(f[S])
{
int len = 0, now = S;
while(now)
{
b[++len] = now % 3;
now /= 3;
}
int len2 = 0;
for(int i = 1;i <= len; i++)
{
if(b[i] == 1)
{
c[++len2] = i;
}
}
for(int i = 1;i <= m; i++)
{
if(b[i])
{
continue;
}
if(bj[i])
{
bool flag = true;
for(int j = 1;j < bj[i]; j++)
{
if(!b[a[j]])
{
flag = false;
break;
}
}
if(!flag)
{
continue;
}
}
if(i > c[len2])
{
if(len2 + 1 <= n)
{
f[S + pow[i - 1]] += f[S];
}
}
else
{
int l = 1, r = len2;
while(l < r)
{
int mid = (l + r) / 2;
if(c[mid] < i)
{
l = mid + 1;
}
else
{
r = mid;
}
}
if(c[l] > i)
{
f[S + pow[c[l] - 1] + pow[i - 1]] += f[S];
}
}
}
bool flag = true;
for(int i = 1;i <= m; i++)
{
if(!b[i])
{
flag = false;
}
}
if(flag)
{
ans += f[S];
}
}
}
printf("%d", ans);
return 0;
}