[Luogu 1410]子序列

Description

给定一个长度为N(N为偶数)的序列,问能否将其划分为两个长度为N/2的严格递增子序列,

Input

若干行,每行表示一组数据。对于每组数据,首先输入一个整数N,表示序列的长度。之后N个整数表示这个序列。

Output

同输入行数。对于每组数据,如果存在一种划分,则输出“Yes!”,否则输出“No!“。

Sample Input

6 3 1 4 5 8 7
6 3 2 1 6 5 4

Sample Output

Yes!
No!

HINT

共三组数据,每组数据行数<=50,0 <= 输入的所有数 <= 10^9

第一组(30%):N <= 20

第二组(30%):N <= 100

第三组(40%):N <= 2000

题解

在前$i$位中找长$j$位的以第$i$位结尾的上升子序列(我们设这个为序列$A$),并且剩下的也是上升子序列(设这个为序列$B$),那么$f[i][j]$表示剩下的(即前i位中长$i-j$位的不以第$i$位结尾的)上升子序列(即序列$B$)的最后一位的最小值。

注意:$A$一定是以最后一个数结尾的。

然后转移:

如果$a[i]<a[i+1]$,那么$f[i+1][j+1] = min(f[i+1][j+1], f[i][j])$,意思就是将$a[i+1]$接在序列$A$后,相当于可以直接把$f[i][j]$扩展到第$i+1$位。

如果$f[i][j]<a[i+1]$,那么$f[i+1][i-j+1] = min(f[i+1][i-j+1], a[i])$,意思是将$a[i+1]$接在$B$后,相当于第$i+1$继承前$i$位中$i-j$位长的上升子序列,此时$B$序列的某尾为最后一个数,那么我们就要$swap(A,B)$。

 1 //It is made by Awson on 2017.9.27
 2 #include <set>
 3 #include <map>
 4 #include <cmath>
 5 #include <ctime> 
 6 #include <queue>
 7 #include <stack>
 8 #include <string>
 9 #include <cstdio>
10 #include <vector>
11 #include <cstdlib>
12 #include <cstring>
13 #include <iostream>
14 #include <algorithm>
15 #define Min(a, b) ((a) < (b) ? (a) : (b))
16 #define Max(a, b) ((a) > (b) ? (a) : (b))
17 #define LL long long
18 using namespace std;
19 const int N = 2000;
20 void read(int &x) {
21     char ch; bool flag = 0;
22     for (ch = getchar(); !isdigit(ch) && ((flag |= (ch == '-')) || 1); ch = getchar());
23     for (x = 0; isdigit(ch); x = (x<<1)+(x<<3)+ch-48, ch = getchar());
24     x *= 1-2*flag;
25 }
26 
27 int n, a[N+5];
28 int f[N+5][N+5];
29 
30 void work() {
31     for (int i = 1; i <= n; i++)
32         read(a[i]);
33     memset(f, 127, sizeof(f));
34     int INF = f[0][0];
35     f[1][1] = -1;
36     for (int i = 1; i <= n; i++)
37         for (int j = 0; j <= i; j++)
38             if (f[i][j] != INF) {
39                 if (a[i] < a[i+1]) f[i+1][j+1] = Min(f[i+1][j+1], f[i][j]);
40                 if (f[i][j] < a[i+1]) f[i+1][i+1-j] = Min(f[i+1][i+1-j], a[i]);
41             }
42     printf(f[n][n/2] == INF ? "No!\n" : "Yes!\n");
43 }
44 int main() {
45     while (~scanf("%d", &n))
46         work();
47     return 0;
48 }

 

posted @ 2017-09-27 20:23  NaVi_Awson  阅读(293)  评论(0编辑  收藏  举报