集合划分——cf1028D思维题

非常思维的一道题目,题意很长

给定s1,s2两个集合,s1维护最大值,s2维护最小值,s1的所有元素要比s2小

操作1:往两个集合里的任意一个添加x

操作2:把x从所在的集合里删掉:要求被删的x必须是s1里最大的元素或s2里最小的元素

因为操作2的要求十分严格。。我们可以想到在最后一次操作2结束前所有的操作1都是确定下来的

那我们先来考虑最后一次操作2之前的操作1:

  每次加x,但是不知道x往哪里加,那就直接用一个大集合S,把x加进去

直到出现一个操作2:操作2给出的x必然在集合S的某个位置,那比x小的元素必定被划分到集合s1中,比x大的元素被划分到s2中,此时之前的操作添加的数都有确定的位置了,并且两个集合的最大值L,最小值R也确定下来了

然后接下去的操作1就是往集合里面加元素,操作2就进行重新划分+更新L,R,并且每次操作2都有两种选择,即x从s1里删去还是从s2里删去 ( 除了两种特殊情况:无解和x恰好==L,R边界 ) 

最后一次操作2后,cnt次操作1添加的数都没有确定的划分,所以再乘上cnt+1种选择

#include<bits/stdc++.h>
#include<set>
using namespace std;
#define ll long long
#define maxn 400005
#define mod 1000000007
#define INF 0x3f3f3f3f3f3f
ll n,x,L,R;
char op[100];
set<ll>s;
set<ll>::iterator it;

int main(){
    cin>>n;ll ans=1;
    L=-INF,R=INF;
    s.insert(INF);s.insert(-INF);
    it=s.begin();
    
    int cnt=0;
    for(int i=1;i<=n;i++){
        scanf("%s%lld",op,&x);
        if(op[1]=='D'){
            if(x>=L && x<=R)cnt++;
            s.insert(x);    
        }
        else {
            cnt=0;
            if(x<L || x>R){
                puts("0");
                return 0;
            }
            else if(x!=L && x!=R)ans=ans*2%mod;
            //这里要注意因为所有的元素都不相等,所以当要删除边界时只有一种选择 
             
            it=s.lower_bound(x);
            it++;R=*it;
            it--;it--;L=*it;
            it++;s.erase(it);
        }
    }
    cout<<ans*(++cnt)%mod<<endl;    
} 
原文地址:https://www.cnblogs.com/zsben991126/p/10816108.html