Codeforces #550 (Div3) - G.Two Merged Sequences(dp / 贪心)

Problem  Codeforces #550 (Div3) - G.Two Merged Sequences

Time Limit: 2000 mSec

Problem Description

Two integer sequences existed initially, one of them was strictly increasing, and another one — strictly decreasing.

Strictly increasing sequence is a sequence of integers [x1<x2<?<xk][x1<x2<?<xk] . And strictly decreasing sequence is a sequence of integers [y1>y2>?>yl][y1>y2>?>yl] . Note that the empty sequence and the sequence consisting of one element can be considered as increasing or decreasing.

Elements of increasing sequence were inserted between elements of the decreasing one (and, possibly, before its first element and after its last element) without changing the order. For example, sequences [1,3,4][1,3,4] and [10,4,2][10,4,2] can produce the following resulting sequences: [10,1,3,4,2,4][10,1,3,4,2,4] , [1,3,4,10,4,2][1,3,4,10,4,2] . The following sequence cannot be the result of these insertions: [1,10,4,4,3,2][1,10,4,4,3,2] because the order of elements in the increasing sequence was changed.

Let the obtained sequence be aa . This sequence aa is given in the input. Your task is to find any two suitable initial sequences. One of them should be strictly increasing, and another one — strictly decreasing. Note that the empty sequence and the sequence consisting of one element can be considered as increasing or decreasing.

If there is a contradiction in the input and it is impossible to split the given sequence aa into one increasing sequence and one decreasing sequence, print "NO".

Input

The first line of the input contains one integer nn (1≤n≤2⋅1051≤n≤2⋅105) — the number of elements in aa.

The second line of the input contains nn integers a1,a2,…,ana1,a2,…,an (0≤ai≤2⋅1050≤ai≤2⋅105), where aiai is the ii-th element of a.

Output

If there is a contradiction in the input and it is impossible to split the given sequence aa into one increasing sequence and one decreasing sequence, print "NO" in the first line.

Otherwise print "YES" in the first line. In the second line, print a sequence of nn integers res1,res2,…,resnres1,res2,…,resn, where resiresi should be either 00 or 11 for each ii from 11 to nn. The ii-th element of this sequence should be 00 if the ii-th element of aa belongs to the increasing sequence, and 11 otherwise. Note that the empty sequence and the sequence consisting of one element can be considered as increasing or decreasing.

Sample Input

9
5 1 3 6 8 2 9 0 10

Sample Output

YES
1 0 0 0 0 1 0 1 0

题解:两种做法,先说贪心,维护下降序列当前最小值M和上升序列当前最大值m

  1、a[i] > M && a[i] < m,自然无解。

  2、a[i] < M && a[i] < m,只能加到下降序列。

  3、a[i] > M && a[i] > m,只能加到上升序列。

  4、a[i] < M && a[i] > m,此时需要考虑a[i+1]与a[i]的大小关系,不妨假设a[i+1] > a[i],那么此时应将a[i]加入上升序列,原因很简单,如果把a[i]加入下降序列,则a[i+1]只能加入上升序列,显然这种方案不如把a[i]与a[i+1]都加入上升序列(下降的没动,上升的变化相同),另一种情况同理。

  以上四点给出贪心算法并说明贪心成立。

  第二种动态规划,分段决策类的动态规划,无非就是考虑第i个数加到上升还是下降,所以很容易想到二维dp,第一维表处理到第i个数,第二维表加入哪个序列,难想的地方在于要优化什么东西,这里的状态定义就很值得学习了:

  dp(i, 0)表示处理完前i个数,将i加入递增序列后递减序列元素中最后一个元素的最大值。

  dp(i, 1)表示处理完前i个数,将i加入递减序列后递增序列元素中最后一个元素的最小值。

我们肯定是希望前者越大越好,后者越小越好,这样给后面的数字提供更大的选择空间,其实这样定义状态看似有点绕,其实很合理,因为把i加入递增序列后,递增序列的最小值就有了,所以只需要再维护一下递减的最大值即可,加入递减序列同理。再说状态转移的问题,一般动态规划都是难在状态,此题也不例外,转移不难,就是枚举a[i]和a[i-1]分别放在哪种序列中即可,转移时要记录路径,方便最后输出。

  贪心代码没啥说的就不贴了,只给出dp代码。

 1 #include <bits/stdc++.h>
 2
 3 using namespace std;
 4
 5 #define REP(i, n) for (int i = 1; i <= (n); i++)
 6 #define sqr(x) ((x) * (x))
 7
 8 const int maxn = 200000 + 100;
 9 const int maxm = 200000 + 100;
10 const int maxs = 10000 + 10;
11
12 typedef long long LL;
13 typedef pair<int, int> pii;
14 typedef pair<double, double> pdd;
15
16 const LL unit = 1LL;
17 const int INF = 0x3f3f3f3f;
18 const LL mod = 1000000007;
19 const double eps = 1e-14;
20 const double inf = 1e15;
21 const double pi = acos(-1.0);
22
23 int n;
24 int a[maxn], dp[maxn][2];
25 int path[maxn][2];
26 int ans[maxn];
27
28 int main()
29 {
30     ios::sync_with_stdio(false);
31     cin.tie(0);
32     //freopen("input.txt", "r", stdin);
33     //freopen("output.txt", "w", stdout);
34     cin >> n;
35     for (int i = 1; i <= n; i++)
36     {
37         cin >> a[i];
38     }
39     dp[1][0] = INF, dp[1][1] = -INF;
40     for (int i = 2; i <= n; i++)
41     {
42         dp[i][0] = -INF, dp[i][1] = INF;
43         if (a[i - 1] < a[i] && dp[i][0] < dp[i - 1][0])
44         {
45             dp[i][0] = dp[i - 1][0];
46             path[i][0] = 0;
47         }
48         if (dp[i - 1][0] > a[i] && dp[i][1] > a[i - 1])
49         {
50             dp[i][1] = a[i - 1];
51             path[i][1] = 0;
52         }
53         if (a[i] > dp[i - 1][1] && dp[i][0] < a[i - 1])
54         {
55             dp[i][0] = a[i - 1];
56             path[i][0] = 1;
57         }
58         if (a[i] < a[i - 1] && dp[i][1] > dp[i - 1][1])
59         {
60             dp[i][1] = dp[i - 1][1];
61             path[i][1] = 1;
62         }
63     }
64     if(dp[n][0] > -INF)
65     {
66         cout << "YES" << endl;
67         int opt = 0;
68         for(int i = n; i >= 1; i--)
69         {
70             ans[i] = opt;
71             opt = path[i][opt];
72         }
73         for(int i = 1; i <= n; i++)
74         {
75             cout << ans[i] << " ";
76         }
77     }
78     else if(dp[n][1] < INF)
79     {
80         cout << "YES" << endl;
81         int opt = 1;
82         for(int i = n; i >= 1; i--)
83         {
84             ans[i] = opt;
85             opt = path[i][opt];
86         }
87         for(int i = 1; i <= n; i++)
88         {
89             cout << ans[i] << " ";
90         }
91     }
92     else
93     {
94         cout << "NO";
95     }
96     return 0;
97 }

原文地址:https://www.cnblogs.com/npugen/p/10777450.html

时间: 2024-08-12 22:07:24

Codeforces #550 (Div3) - G.Two Merged Sequences(dp / 贪心)的相关文章

Codeforces 1144G Two Merged Sequences dp

Two Merged Sequences 感觉是个垃圾题啊, 为什么过的人这么少.. dp[ i ][ 0 ]表示处理完前 i 个, 第 i 个是递增序列序列里的元素,递减序列的最大值. dp[ i ][ 1 ]表示处理完前 i 个, 第 i 个是递减序列序列里的元素,递增序列的最小值. 然后随便转移转移顺便记录一下路径就好啦. #include<bits/stdc++.h> #define LL long long #define fi first #define se second #de

Educational Codeforces Round 21 G. Anthem of Berland(dp+kmp)

题目链接:Educational Codeforces Round 21 G. Anthem of Berland 题意: 给你两个字符串,第一个字符串包含问号,问号可以变成任意字符串. 问你第一个字符串最多包含多少个第二个字符串. 题解: 考虑dp[i][j],表示当前考虑到第一个串的第i位,已经匹配到第二个字符串的第j位. 这样的话复杂度为26*n*m*O(fail). fail可以用kmp进行预处理,将26个字母全部处理出来,这样复杂度就变成了26*n*m. 状态转移看代码(就是一个kmp

Codeforces Round #276 (Div. 1)D.Kindergarten DP贪心

D. Kindergarten In a kindergarten, the children are being divided into groups. The teacher put the children in a line and associated each child with his or her integer charisma value. Each child should go to exactly one group. Each group should be a

Codeforces 77C 树形dp + 贪心

题目链接:点击打开链接 题意: 给定n个点, 每个点的豆子数量 下面是一棵树 再给出起点 每走到一个点,就会把那个点的豆子吃掉一颗. 问:回到起点最多能吃掉多少颗豆子 思路:树形dp 对于当前节点u,先把子节点v都走一次. 然后再往返于(u,v) 之间,直到u点没有豆子或者v点没有豆子. dp[u] 表示u点的最大值.a[u] 是u点剩下的豆子数. #include <cstdio> #include <vector> #include <algorithm> #inc

Educational Codeforces Round 25 G. Tree Queries

题目链接:Educational Codeforces Round 25 G. Tree Queries 题意: 给你一棵树,一开始所有的点全是黑色,有两种操作. 1 x 将x这个点变为黑色,保证第一个操作是这个. 2 x 询问x到任意黑色的点的简单路径上的最小节点编号. 题解: 首先将一个变为黑色的点当成树根,然后dfs一下,预处理出所有点的答案. 然后开一个变量记录一下当前变黑的点的答案cur=min(cur,dp[x]). 每次询问的时候答案就是min(cur,dp[x]). 如果觉得很神

codeforces 161D - Distance in Tree(树形dp)

题目大意: 求出树上距离为k的点对有多少个. 思路分析: dp[i][j] 表示 i 的子树中和 i 的距离为 j 的点数有多少个.注意dp[i] [0] 永远是1的. 然后在处理完一颗子树后,就把自身的dp 更新. 更新之前更新答案. 如果这颗子树到 i 有 x 个距离为j的.那么答案就要加上 dp[i] [ k-j-1] * x; #include <iostream> #include <cstdio> #include <cstring> #include &l

CodeForces 258B Little Elephant and Elections 数位DP

前面先用数位DP预处理,然后暴力计算组合方式即可. #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include

Codeforces 437E The Child and Polygon(区间DP)

题目链接:Codeforces 437E The Child and Polygon 题目大意:给出一个多边形,问说有多少种分割方法,将多边形分割为多个三角形. 解题思路:首先要理解向量叉积的性质,一开始将给出的点转换成顺时针,然后用区间dp计算.dp[i][j]表示从点i到点j可以有dp[i][j]种切割方法.然后点i和点j是否可以做为切割线,要经过判断,即在i和j中选择的话点k的话,点k要在i,j的逆时针方. #include <cstdio> #include <cstring&g

Codeforces 219D. Choosing Capital for Treeland (树dp)

题目链接:http://codeforces.com/contest/219/problem/D 树dp 1 //#pragma comment(linker, "/STACK:102400000, 102400000") 2 #include <algorithm> 3 #include <iostream> 4 #include <cstdlib> 5 #include <cstring> 6 #include <cstdio&