zoukankan      html  css  js  c++  java
  • 解题:POI 2018 Prawnicy

    题面

    网上好像都是堆的做法啊......我这个不算离散化是$O(n)$的说(虽然有一坨vector可能不开O2会爆炸)

    题目即是让我们求是否存在一个最长的是不少于$k$个给出区间子集的区间,如果存在输出方案。我们发现当我们的左端点固定时,右端点越向右越可能不合法,但同时答案在不断扩大(好像不太严谨),这给了我们一个更新答案的条件;而当右端点固定左端点向右移动时,答案只会越来越合法同时越来越不优。这样我们就可以尺取做了,问题是如何统计当前区间是几个区间的子集呢?

    事实上这不需要任何数据结构,我们将每个区间拆成左右端点分别用vector存起来,同时开一个数组用来标记,然后当我们的指针遇到区间时讨论:

    如果左指针碰到左端点,检查一下这个区间的右端点是否在右指针右边,如果在且这个区间还没被标记,则标记它并记录贡献

    如果右指针扫过右端点(注意是扫过),检查一下这个区间是否被标记,如果被标记则移除它的贡献

    如果右指针碰到右端点,检查一下这个区间的左端点是否在左指针左边,如果在且这个区间还没被标记,则标记它并记录贡献

    这样如果不算离散化就是$O(n)$的辣

     1 #include<cstdio>
     2 #include<vector>
     3 #include<cstring>
     4 #include<utility>
     5 #include<algorithm>
     6 using namespace std;
     7 const int N=1000005;
     8 vector<pair<int,int> > ln[2*N],rn[2*N];
     9 int n,k,c,p1,p2,a1,a2,cnt,xnt,tot,ans;
    10 int ll[N],rr[N],uni[2*N],mark[N];
    11 void renew(int typ)
    12 {
    13     if(!typ)
    14     {
    15         for(int i=0;i<(int)ln[p1].size();++i)
    16             if(ln[p1][i].first>=p2) 
    17                 if(!mark[ln[p1][i].second])
    18                     mark[ln[p1][i].second]=true,xnt++;
    19     }
    20     else
    21     {
    22         for(int i=0;i<(int)rn[p2-1].size();i++)
    23             if(mark[rn[p2-1][i].second])
    24                 mark[rn[p2-1][i].second]=false,xnt--;
    25         for(int i=0;i<(int)rn[p2].size();i++)
    26             if(rn[p2][i].first<=p1)
    27                 if(!mark[rn[p2][i].second])
    28                     mark[rn[p2][i].second]=true,xnt++;
    29     }
    30 }
    31 int main ()
    32 {
    33     scanf("%d%d",&n,&k);
    34     for(int i=1;i<=n;i++)
    35     {
    36         scanf("%d%d",&ll[i],&rr[i]);
    37         uni[++tot]=ll[i],uni[++tot]=rr[i];
    38     }
    39     sort(uni+1,uni+1+tot),tot=unique(uni+1,uni+1+tot)-uni-1;
    40     for(int i=1;i<=n;i++)
    41     {
    42         ll[i]=lower_bound(uni+1,uni+1+tot,ll[i])-uni;
    43         rr[i]=lower_bound(uni+1,uni+1+tot,rr[i])-uni;
    44         ln[ll[i]].push_back(make_pair(rr[i],i));
    45         rn[rr[i]].push_back(make_pair(ll[i],i));
    46     }
    47     p1=p2=0; 
    48     while(p1<=tot&&p2<=tot)
    49     {
    50         if(p1>p2) p2=p1,renew(1); 
    51         if(xnt>=k) 
    52         {
    53             while(xnt>=k&&p2<=tot) p2++,renew(1); 
    54             if(uni[p2-1]-uni[p1]>ans) ans=max(ans,uni[p2-1]-uni[p1]),a1=p1,a2=p2-1; 
    55         }
    56         p1++,renew(0);
    57     }
    58     printf("%d
    ",ans); 
    59     for(int i=1;i<=n&&c<k;i++)
    60         if(ll[i]<=a1&&rr[i]>=a2)
    61             printf("%d ",i),c++;
    62     return 0;
    63 }
    View Code
  • 相关阅读:
    个人主页
    本周个人总结
    周个人总结
    排球比赛计分程序的典型用户和场景
    排球比赛计分规则功能说明书
    [黑马程序员]入学面试题!
    [黑马论坛]24期技术活动题目及答案!
    [黑马论坛]23期技术活动题目及答案!
    [黑马程序员]训练营入学考试题!
    [黑马程序员]基础测试题目!
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9861471.html
Copyright © 2011-2022 走看看