2020ICPC·小米 网络选拔赛第二场 Subsequence Pair(贪心二分)

在这里插入图片描述
题意:
一个只含有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;
}


©️2020 CSDN 皮肤主题: 撸撸猫 设计师:设计师小姐姐 返回首页