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
  • 相关阅读:
    Java学习二十九天
    Java学习二十八天
    47. Permutations II 全排列可重复版本
    46. Permutations 全排列,无重复
    subset ii 子集 有重复元素
    339. Nested List Weight Sum 339.嵌套列表权重总和
    251. Flatten 2D Vector 平铺二维矩阵
    217. Contains Duplicate数组重复元素
    209. Minimum Size Subarray Sum 结果大于等于目标的最小长度数组
    438. Find All Anagrams in a String 查找字符串中的所有Anagrams
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/9861471.html
Copyright © 2011-2022 走看看