2019年杭电多校第二场 1002题Beauty Of Unimodal Sequence(LIS+单调栈)

题目链接

传送门

思路

首先我们对\(a\)正反各跑一边\(LIS\),记录每个位置在前一半的\(LIS\)中应该放的位置\(ans1[i]\),后一半的位置\(ans2[i]\)。

对于字典序最小的方案,我们找到第一个峰值,然后往前遍历。在\(i\)这个位置,如果它在\(LIS\)中放的位置是\(pos\),那么我们先看当前放在\(pos+1\)的值是否比它大,大的话就说明这个位置一定比前面放过在\(pos\)这个位置的更优(因为字典序更小,且\([1,i]\)一定可以放满\([1,pos-1]\)),然后我们就用单调栈把当前放的小于等于\(pos\)的值全部\(pop\)掉。对于后一半的我们就直接对于每个可以放的位置反复覆盖即可。

对于字典序最大的我们则就是前一半反复覆盖,后一半用单调栈维护,与字典序刚好相反。

代码实现如下

#include <set>
#include <map>
#include <deque>
#include <queue>
#include <stack>
#include <cmath>
#include <ctime>
#include <bitset>
#include <cstdio>
#include <string>
#include <vector>
#include <cassert>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;

typedef long long LL;
typedef pair<LL, LL> pLL;
typedef pair<LL, int> pLi;
typedef pair<int, LL> pil;;
typedef pair<int, int> pii;
typedef unsigned long long uLL;

#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) x&(-x)
#define name2str(name) (#name)
#define bug printf("*********\n")
#define debug(x) cout<<#x"=["<<x<<"]" <<endl
#define FIN freopen("/home/dillonh/CLionProjects/Dillonh/in.txt","r",stdin)
#define IO ios::sync_with_stdio(false),cin.tie(0)

const double eps = 1e-8;
const int mod = 998244353;
const int maxn = 3e5 + 7;
const double pi = acos(-1);
const int inf = 0x3f3f3f3f;
const LL INF = 0x3f3f3f3f3f3f3f3fLL;

int n;
stack<int> st;
vector<int> vec, v;
int pos[maxn];
int a[maxn], dp[maxn], ans1[maxn], ans2[maxn];

int main() {
#ifndef ONLINE_JUDGE
    FIN;
#endif
    while(~scanf("%d", &n)) {
        memset(dp, inf, sizeof(dp));
        dp[0] = 0;
        for(int i = 1; i <= n; ++i) {
            scanf("%d", &a[i]);
            ans1[i] = ans2[i] = 0;
            pos[i] = inf;
            ans1[i] = lower_bound(dp + 1, dp + n + 1, a[i]) - dp;
            dp[ans1[i]] = a[i];
        }
        memset(dp, inf, sizeof(dp));
        dp[0] = 0;
        for(int i = n; i >= 1; --i) {
            ans2[i] = lower_bound(dp + 1, dp + n + 1, a[i]) - dp;
            dp[ans2[i]] = a[i];
        }
        while(!st.empty()) st.pop();
        int idx = 1, mx = ans1[1] + ans2[1];
        for(int i = 2; i <= n; ++i) {
            if(ans1[i] + ans2[i] > mx) {
                idx = i;
                mx = ans1[i] + ans2[i];
            }
        }
        pos[ans1[idx]] = a[idx];
        for(int i = idx - 1; i >= 1; --i) {
            if(ans1[i] >= ans1[idx]) continue;
            if(pos[ans1[i]+1] <= a[i]) continue;
            while(!st.empty() && ans1[i] >= ans1[st.top()]) {
                pos[ans1[st.top()]] = inf;
                st.pop();
            }
            st.push(i);
            pos[ans1[i]] = a[i];
        }
        vec.clear();
        while(!st.empty()) {
            vec.push_back(st.top());
            st.pop();
        }
        vec.push_back(idx);
        int las = idx;
        for(int i = idx + 1; i <= n; ++i) {
            if(ans2[i] == ans2[las] - 1 && a[i] < a[las]) {
                vec.push_back(i);
                las = i;
            }
        }
        int flag = 0;
        for(auto x:vec) {
            if(flag) printf(" ");
            flag = 1;
            printf("%d", x);
        }
        printf("\n");

        vec.clear();
        idx = 1, mx = ans1[1] + ans2[1];
        for(int i = 2; i <= n; ++i) {
            if(ans1[i] + ans2[i] >= mx) {
                idx = i;
                mx = ans1[i] + ans2[i];
            }
        }
        las = idx;
        vec.push_back(idx);
        for(int i = idx - 1; i >= 1; --i) {
            if(ans1[i] == ans1[las] - 1 && a[i] < a[las]) {
                vec.push_back(i);
                las = i;
            }
        }
        reverse(vec.begin(), vec.end());
        for(int i = 1; i<= n; ++i) pos[i] = inf;
        pos[ans2[idx]] = a[idx];
        while(!st.empty()) st.pop();
        for(int i = idx + 1; i <= n; ++i) {
            if(ans2[i] > ans2[idx]) continue;
            if(a[i] >= pos[ans2[i]+1]) continue;
            while(!st.empty() && ans2[i] >= ans2[st.top()]) {
                pos[ans2[st.top()]] = inf;
                st.pop();
            }
            st.push(i);
            pos[ans2[st.top()]] = a[i];
        }
        v.clear();
        while(!st.empty()) {
            v.push_back(st.top());
            st.pop();
        }
        reverse(v.begin(), v.end());
        flag = 0;
        for(auto x:vec) {
            if(flag) printf(" ");
            flag = 1;
            printf("%d", x);
        }
        for(auto x:v) {
            if(flag) printf(" ");
            flag = 1;
            printf("%d", x);
        }
        printf("\n");
    }
    return 0;
}

原文地址:https://www.cnblogs.com/Dillonh/p/11240083.html

时间: 2024-10-18 06:40:12

2019年杭电多校第二场 1002题Beauty Of Unimodal Sequence(LIS+单调栈)的相关文章

2019年杭电多校第九场07题(HDU6686+树形dp)

目录 题目链接 题意 思路 代码 题目链接 传送门 题意 定义\(L(a,b)\)为结点\(a\)到结点\(b\)的路径上的结点数,问有种\(pair(L(a,b),L(c,d))\)取值,其中结点\(a\)到结点\(b\)的路径与结点\(c\)到结点\(d\)的路径没有交叉. 思路 我们很容易想到要想两条路径不交叉,那么\(a,b\)与\(c,d\)必定在两棵不同的子树中,假设第一棵子树的直径位\(L1\),第二棵子树的直径为\(L2\),那么我们可以得知\([1,L1]\)必定可以与\([1

2019 杭电多校 第二场

2019 Multi-University Training Contest 2 补题链接:2019 Multi-University Training Contest 2 1005 Everything Is Generated In Equal Probability (HDU-6595) 题意 给出一个整数 \(N\),在 \([1,N]\) 中随机生成一个 \(n\).然后生成长度为 \(n\) 的全排列 \([1, n]\). 对该排列运行一个程序,程序先求当前排列的逆序对对数,然后随

2019杭电多校第二场hdu6602 Longest Subarray(线段树)

Longest Subarray 题目传送门 解题思路 本题求一个最大的子区间,满足区间内的数字要么出现次数大于等于k次,要么没出现过.给定区间内的数字范围是1~c. 如果r为右边界,对于一种数字x,满足条件的左边界l的范围是r左边第一个x出现的位置+1(即这段区间内没有出现过x,如果x在1~r内都没有出现过,那么1~r自然都是l的合法范围),以及1到从右往左数数第k个x出现的位置(即这段区间内的x出现次数大于等于k).所以我们只要找到同时是c种数字的合法左边界的位置中最小的,然后枚举所有的i作

2015杭电多校第二场

Buildings Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1622    Accepted Submission(s): 460 Problem Description Your current task is to make a ground plan for a residential building located

杭电多校第一场补题-1002 Balanced Sequence

1002: Balanced Sequence 题意:给定n个字符串,n的大小在1e5左右,字符串的长度也是1e5,字符串仅由'('或')'组成,合法串可以不是连续的,将这n个串按照一定的顺序排列起来,使得组合之后的字符串的合法串的长度最长.n*len的大小是1e6 思路:首先n*len的处理出来每一个字符串中合法的长度,处理的办法可以参考之前栈的想法,每遇见一个')',就判断前面'('的个数,只要不为0,此时就可以合成一个合法串,处理完之后可以得到剩下的')'和'('的个数,然后所有的n个串进

2019杭电多校第九场

2019杭电多校第九场 熟悉的后半场挂机节奏,又苟进首页了,很快乐 1001. Rikka with Quicksort upsolved 不是我做的,1e9调和级数分段打表 1002. Rikka with Cake solved at 01:11 有一个矩形,给你很多射线(射线只有横平竖直的四个方向),问把矩形切成了多少块 队友说答案是交点数加一,作为一个合格的工具人,当然是把队友的想法实现啦 二维坐标离散化枚举纵坐标维护横坐标,常规套路,树状数组也可以做(我是线段树写习惯了根本没想起来还有

HDU 4920(杭电多校训练#5 1010 题) Matrix multiplication(不知道该挂个什么帽子。。。)

题目地址:HDU 4920 对这个题简直无语到极点...居然O(n^3)的复杂度能过....方法有三.. 1:进行输入优化和输出优化..(前提是你的输入优化不能太搓...) 2:利用缓存优化..详情请看该论文.大体就是将后两个for循环换过来,让坐标改变的频率降下来. 3:叉姐题解中说的正规方法..利用biset存储,进行预处理..(其实我还没看懂.. 我只写了个第二种...代码如下,共勉..神奇的小代码.. #include <iostream> #include <cstdio>

HDU 4901(杭电多校训练#3 1005题)The Romantic Hero(DP)

题目地址:HDU 4901 这题没想到最后居然能够做出来.... 这题用了两次DP,先从前往后求一次异或的,再从后往前求一次与运算的.分别是 1:求异或的时候,定义二维数组huo[1000][1024],前者指第几位,后者是哈希的思想,若huo[x][y]=2则表示最右边的数为第x位时,异或值为y的出现了两次,需要再定义一个hash数组,来保存前面出现的所有情况,再找有多少位的时候,用hash数组中出现的所有的值与当前的第x位的数字进行异或. 2:求与的时候,定义二维数组yu[1000][102

【2019.07.22】2019杭电多校第一场

补题地址:http://acm.hdu.edu.cn/listproblem.php?vol=56 题号:6578-6590 1001: 1002:线性基 https://blog.csdn.net/Cassie_zkq/article/details/96979461 1003: 1004: 1005:? 1006: 1007: 1008: 1009: 1010: 1011: 1012: 1013: 自闭场,但补题能学到好多算法和思维,继续加油鸭- 原文地址:https://www.cnblo