• [atAGC013F]Two Faced Cards


    先对$c_{i}$离散到$[0,n]$上,并令$a_{i},b_{i},d_{i},e_{i}$对应到第一个大于等于他的数

    考虑若$a_{n+1}$和$b_{n+1}$也已经确定如何做:

    有一个$o(2^{n})$的暴力,即暴力确定每一个数是选择$a_{i}$还是$b_{i}$,记这些数依次为$p_{i}$,贪心去匹配,即将两者从小到大排序后有$p_{i}le c_{i}$

    事实上,可以通过以下方式来判定:对于一个初始为0的数组,对所有$[p_{i},n]$加1,对所有$[c_{i},n]$减1,合法当且仅当所有位置都非负

    证明:若$p_{i}le c_{i}$,必然非负,同时若存在非负的位置$x$,即$sum[xge p_{i}]-[xge c_{i}]<0$,对两者排序后,有$p_{i}中第一个大于x的位置<c_{i}中第一个大于x的位置$,记前者为$k$,则$p_{k}>xge c_{k}$

    接下来,先全部令$p_{i}=a_{i}$,此时会有若干个位置小于0,然后可以对$[b_{i},a_{i})$这个区间加1,即表示令$p_{i}=$改为选择$b_{i}$,选择尽量少的区间使得最终非负(特别的,若$b_{i}>a_{i}$一定不会选择,删去此类区间)

    同样可以贪心,即对于$k=max_{a_{i}<0}i$(若不存在即结束),必然选择包含$k$且左端点最小的区间,重复此过程,通过set维护最小左端点即可得到最优解,复杂度为$o(qnlog_{2}n)$

    证明:对$i$之后的位置加1没有意义,因此右端点可以对$i$取min,两个相互包含的区间取较大的区间更优(另外不一定要保证在左端点最小的同时右端点最大)

    接下来,由于仅有$n+1$变化,不妨$o(2)$去枚举最后一个点的选择,之后相当于询问对某一个后缀全部加1后的答案,也可以看作这个后缀要求大于等于-1即可

    类似的贪心,即对于$k=max_{a_{i}<-1}i$,必然选择包含$k$左端点最小的区间(不论对什么后缀加1)

    证明:假设对$[x,n]$这个后缀加1,若$xle k$则$k=max_{a_{i}<0}i$,因此必然修改;若$x>k$则$k$之后至多只有一个操作包含$k$,因为对于这样一个操作以后$k$之后所有数都变得非负了,此时$a_{k}<0$,因此仍要对$k$修改

    (这里并不一定选择左端点最小的,因为可能上次包含$k$的操作就是左端点最小的,但必然是选择的)

    同样重复这个过程,选出必选的区间,此时所有位置都大于等于-1

    此时我们从左到右,对$a_{i}=-1$的位置求出仅考虑$i$以前(包括$i$)的所有-1,那么必然选择包含$i$且左端点最小的区间,然后变成了一个前缀的子问题,记录一下答案即可

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N 100005
     4 vector<int>v[N];
     5 multiset<pair<int,int> >s;
     6 int n,m,x,y,tot,a[N],b[N],c[N],f[N],ans[N];
     7 bool cmp(int x,int y){
     8     return x>y;
     9 }
    10 int find(int k){
    11     return lower_bound(c,c+n+1,k)-c;
    12 }
    13 void update(int l,int r,int p){
    14     f[r]+=p;
    15     if (l)f[l-1]-=p;
    16 }
    17 int main(){
    18     scanf("%d",&n);
    19     for(int i=1;i<=n;i++)scanf("%d%d",&a[i],&b[i]);
    20     for(int i=0;i<=n;i++)scanf("%d",&c[i]);
    21     scanf("%d",&m);
    22     sort(c,c+n+1);
    23     for(int i=0;i<=n;i++)update(find(c[i]),n,-1);
    24     for(int i=1;i<=n;i++){
    25         b[i]=min(b[i],a[i]);
    26         if (b[i]>c[n]){
    27             for(int i=1;i<=m;i++)printf("-1
    ");
    28             return 0;
    29         }
    30         if (a[i]>c[n]){
    31             update(find(b[i]),n,1);
    32             tot++;
    33             continue;
    34         }
    35         a[i]=find(a[i]);
    36         b[i]=find(b[i]);
    37         update(a[i],n,1);
    38         if (b[i]<a[i])v[a[i]-1].push_back(b[i]);
    39     }
    40     for(int i=0;i<=n;i++)sort(v[i].begin(),v[i].end(),cmp);
    41     int sum=0;
    42     for(int i=n;i>=0;i--){
    43         sum+=f[i];
    44         for(int j=0;j<v[i].size();j++)s.insert(make_pair(v[i][j],i));
    45         while (sum<-1){
    46             if ((!s.size())||((*s.begin()).first>i)){
    47                 for(int i=1;i<=m;i++)printf("-1
    ");
    48                 return 0;
    49             }
    50             int k=(*s.begin()).second;
    51             s.erase(s.begin());
    52             tot++;
    53             update(v[k].back(),k,1);
    54             v[k].pop_back();
    55             sum++;
    56         }
    57     }
    58     for(int i=n;i;i--)f[i-1]+=f[i];
    59     for(int i=0;i<=n;i++)v[i].clear();
    60     while (!s.empty()){
    61         v[(*s.begin()).first].push_back((*s.begin()).second);
    62         s.erase(s.begin());
    63     }
    64     for(int i=0;i<=n;i++){
    65         for(int j=0;j<v[i].size();j++)s.insert(make_pair(i,v[i][j]));
    66         if (f[i]>=0)ans[i]=ans[i-1];
    67         else{
    68             if (!s.size()){
    69                 ans[i]=0x3f3f3f3f;
    70                 continue;
    71             }
    72             int k=(*s.begin()).first;
    73             if (!k)ans[i]=1;
    74             else ans[i]=ans[k-1]+1;
    75         }
    76         while ((s.size())&&((*s.begin()).second<=i))s.erase(s.begin());
    77     }
    78     for(int i=1;i<=m;i++){
    79         scanf("%d%d",&x,&y);
    80         int k=-1;
    81         if (x<=c[n]){
    82             if (x<=c[0])k=max(k,n-tot+1);
    83             else k=max(k,n-(ans[find(x)-1]+tot)+1);
    84         }
    85         if (y<=c[n]){
    86             if (y<=c[0])k=max(k,n-tot);
    87             else k=max(k,n-(ans[find(y)-1]+tot));
    88         }
    89         printf("%d
    ",k);
    90     }
    91 }
    View Code
  • 相关阅读:
    MKMapViewDelegate
    MKMapView
    正则表达式随手篇
    c#多线程
    sql模糊查询效率
    c#多线程,进度条,实时给前台发送数据
    如何使用CocoaPods
    TabBar自定义方式(一)
    Spring MVC 学习资料
    优化Myeclipse10 Building Workspace速度慢等问题
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14209775.html
Copyright © 2020-2023  润新知