2020ICPC·小米 網路選拔賽第二場 Subsequence Pair(貪心二分)

tomjobs發表於2020-10-31

在這裡插入圖片描述
題意:
一個只含有0,1,2的序列,要求選出最多的2,0,2,0子序列,且子序列之間沒有交集。

思路:
二分選了mid個2020,然後從前往後找mid個20序列,再從後往前找出剩餘所有的20序列。

前面部分的20序列優先按照0的座標(右端點)排序,後面部分的20序列優先按照2的座標(左端點排序),然後兩者匹配看能否滿足要求。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <vector>

using namespace std;

const int maxn = 2e5 + 7;
int a[maxn],vis[maxn];
int n;

int cmp1(pair<int,int>p1,pair<int,int>p2) {
    if(p1.first != p2.first) return p1.first < p2.first;
    return p1.second < p2.second;
}

int cmp2(pair<int,int>p1,pair<int,int>p2) {
    if(p1.second != p2.second) return p1.second < p2.second;
    return p1.first < p2.first;
}

bool check(int mid) { //
    for(int i = 1;i <= n;i++) vis[i] = 0;
    vector<pair<int,int>>Q1;
    vector<pair<int,int>>Q2;
    queue<int>q0,q2;
 
    for(int i = 1;i <= n;i++) {
        if(a[i] == 0) {
            if(!q2.empty()) {
                int now = q2.front();q2.pop();
                vis[now] = 1;vis[i] = 1;
                Q1.push_back({now,i});
            }
        } else if(a[i] == 2) {
            q2.push(i);
        }
        if(Q1.size() >= mid) break;
    }
    
    for(int i = n;i >= 1;i--) {
        if(vis[i]) continue;
        if(a[i] == 2) {
            if(!q0.empty()) {
                int now = q0.front();q0.pop();
                vis[now] = 1;vis[i] = 1;
                Q2.push_back({i,now});
            }
        } else if(a[i] == 0) {
            q0.push(i);
        }
    }
    sort(Q1.begin(),Q1.end(),cmp2);
    sort(Q2.begin(),Q2.end(),cmp1);
    
    if(Q1.size() < mid) return false;
    int t = 0;

    for(int i = 0;i < Q1.size();i++) {
        int flag = 0;
        while(t < Q2.size()) {
            if(Q2[t].first > Q1[i].second) {
                flag = 1;
                t++;
                break;
            }
            t++;
        }
        if(!flag) return false;
    }
    return true;
}

int main() {
    while(~scanf("%d",&n)) {
        for(int i = 1;i <= n;i++) {
            scanf("%1d",&a[i]);
        }
        int l = 0,r = n / 2;
        int ans = 0;
        while(l <= r) {
            int mid = (l + r) >> 1;
            if(check(mid)) {
                ans = mid;
                l = mid + 1;
            } else {
                r = mid - 1;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}


相關文章