• Codeforces Round #658 (Div. 2) D


    D. Unmerge

    题目链接

    题目:

    判断是否存在长都为n的两个数组 a[ ] , b[ ]

    每次 :

    如果 a 的第一个元素 小于 b的第一个元素

    就把 a的第一个元素 存到 c 中 ,然后 a 的第一个元素弹出

    反之 就把 b的第一个元素 存到 c 中 ,然后 b 的第一个元素弹出

    最后得到了一个数组 c [ ]

    题目给你一个数组c , 问是否存在数组 a[] , b[] , 是就输出 YES

    大家模拟一下就可以把题目转化成:

      从 c 的第一个元素开始 ,当前位置为i ,  找 距离最近的 比当前数大的数的位置 pos( 用单调栈 ) 

      然后 c[ i ~ pos - 1] 这段且要么在 a[] , 要么在 b[]

      于是我们把c数组分成很多个块 , 然后进行分配 , 判断是否可以使得刚好分配均匀(a[] 、b[] 长度为n)

    我的做法是:

    ① 单调栈判断 距离最近的 比当前数大的数的位置 pos

    ② 进行分块 , 用 vec 记录分块的大小

    ③ 判断是否有几块加起来等于 n (代码是 n / 2 因为我一开始 n *= 2)  

    详细看代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn =  2e6 + 10;
    #define ll long long
    #define ios std::ios::sync_with_stdio(false)
    #define int long long
    template<typename T>void read(T &res){bool flag=false;char ch;while(!isdigit(ch=getchar()))(ch=='-')&&(flag=true);
    for(res=ch-48;isdigit(ch=getchar());res=(res<<1)+(res<<3)+ch - 48);flag&&(res=-res);}
    #define pb(a) push_back(a)
    #define cn cout << '
    '
    int a[maxn];
    int pos[maxn]; ///记录距离最近的 比a[i]大的数的位置
    int sta[maxn]; ///单调栈
    int cnt = 0;
    vector<int> vec;///存块
    int dp[maxn];///dp[i]表示dp[i]出现过了吗 , 出现了几次
    map<int , int> ma; ///ma[x] 代表 x 本次出现的次数 , 往下看
    signed main()
    {
        ios,cin.tie(0);
        int t;
        read(t);
        while(t --){
            ma.clear();
            vec.clear();
            cnt = 0;
            int n;
            read(n);
            n *= 2;
            for(int i = 1 ; i <= n ; i ++) read(a[i]) , dp[i] = 0 , pos[i] = 0;
            for(int i = 1 ; i <= n ; i ++){
                while(a[sta[cnt]] < a[i] && cnt > 0){///单调栈
                    pos[sta[cnt --]] = i;
                }
                sta[++ cnt] = i;
            }
            for(int i = 1 ; i <= n ; i ++){
                if(pos[i] == 0){///如果是最大的数 , 因为我最大的数肯定留在栈底出不来, 所以他的pos = 0
                    vec.pb(n - i + 1);///i ~ n 这一大块
                    break;
                }
                else{
                    vec.pb(pos[i] - i);///i ~ pos[i- 1]
                    i = max(i , pos[i] - 1);///i 跳一下
                }
            }
            //for(int i = 0 ; i < vec.size() ; i ++) cout << "sb : " << vec[i] << ' ';
            for(int i = 0 ; i < vec.size() ; i ++){///判断若干个vec[i]能不能组成 n / 2
                if(dp[n / 2])break;
                if(vec[i] > n / 2) break;
                dp[vec[i]] ++; 
                ma.clear();
                ma[vec[i]] ++; /// 本次出现了vec[i]
                for(int j = 1 ; j <= n / 2 ; j ++){
                    if(dp[j] > ma[j] && dp[j] > 0){/// 如果j总共出现的次数大于本次出现的次数
                        ///也就是在取当前数之前,这个dp[j]就 > 0 了 , 这样不会重复计算
                        dp[j + vec[i]] ++;///那 j + vec[i] 
                        ma[j + vec[i]] ++;
                    }
                }
            }
            if(dp[n / 2]) cout << "YES
    ";
            else cout << "NO
    ";
    
        }
        return 0;
    }
    View Code

    最后一段还可以简化一下(感谢G爷):

  • 相关阅读:
    【BZOJ 3098】 Hash Killer II
    【BZOJ 1189】[HNOI2007]紧急疏散evacuate
    【BZOJ 1088】 [SCOI2005]扫雷Mine
    【BZOJ 1821】 [JSOI2010]Group 部落划分 Group
    【BZOJ 1013】 [JSOI2008]球形空间产生器sphere
    【BZOJ 1084】[SCOI2005]最大子矩阵
    【BZOJ 1085】 [SCOI2005]骑士精神
    JNday6-pm
    JNday6-am
    JNday5-pm
  • 原文地址:https://www.cnblogs.com/GoodVv/p/13437461.html
Copyright © 2020-2023  润新知