1. 程式人生 > 實用技巧 >Codeforces Round #658 (Div. 2) D

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 << '\n' 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\n"; else cout << "NO\n"; } return 0; }
View Code

最後一段還可以簡化一下(感謝G爺):