zoukankan      html  css  js  c++  java
  • 【BZOJ】【1293】【SCOI2009】生日礼物

    二分/堆


      求一个最小的区间使得包含所有的颜色(并不一定只出现一次)$nleq 10^6$

      我想的做法是:二分这个最小的长度(满足单调性……好久才想到QAQ),然后O(n)判断是否有可行的区间,这一步可以用一个队列来维护,统计区间内颜色的数量(应该不难吧……)如果队首与队尾元素距离>mid就弹队首= =

      zyf有一个更加优秀的算法:用一个堆来维护左节点……还是引用吧:

     题解:
    考虑到如果线段的左端点定了,那么每种肯定会选离这个端点最近的而又在这个端点右边的彩珠。
    所以我们维护一个k个元素的堆,每次取出队首元素将其弹出,加入它所属种类的下一个彩珠
    如果当前取出的彩珠是该种类彩珠的最后一个,那么跳出循环,输出答案。
    我用的vector和priority_queue
     1 /**************************************************************
     2     Problem: 1293
     3     User: Tunix
     4     Language: C++
     5     Result: Accepted
     6     Time:2608 ms
     7     Memory:12992 kb
     8 ****************************************************************/
     9  
    10 //Huce #1 A
    11 #include<vector>
    12 #include<cstdio>
    13 #include<cstring>
    14 #include<cstdlib>
    15 #include<iostream>
    16 #include<algorithm>
    17 #define rep(i,n) for(int i=0;i<n;++i)
    18 #define F(i,j,n) for(int i=j;i<=n;++i)
    19 #define D(i,j,n) for(int i=j;i>=n;--i)
    20 #define pb push_back
    21 using namespace std;
    22 inline int getint(){
    23     int v=0,sign=1; char ch=getchar();
    24     while(ch<'0'||ch>'9'){ if (ch=='-') sign=-1; ch=getchar();}
    25     while(ch>='0'&&ch<='9'){ v=v*10+ch-'0'; ch=getchar();}
    26     return v*sign;
    27 }
    28 const int N=1e6+10,INF=~0u>>2;
    29 typedef long long LL;
    30 /******************tamplate*********************/
    31 struct data{int v,pos;}a[N];
    32 inline bool cmp(data a,data b){return a.pos<b.pos;}
    33 int cnt[100],Q[N],n,t,tot;
    34  
    35 bool check(int x){
    36     memset(cnt,0,sizeof cnt);
    37     int l=0,r=-1,num=0;
    38     F(i,1,n){
    39         Q[++r]=i;
    40         cnt[a[Q[r]].v]++;
    41         if (cnt[a[Q[r]].v]==1) num++;
    42         while (a[Q[r]].pos-a[Q[l]].pos>x){
    43             cnt[a[Q[l]].v]--;
    44             if (cnt[a[Q[l]].v]==0) num--;
    45             l++;
    46         }
    47         if (num==t) return 1;
    48     }
    49     return 0;
    50 }
    51 int main(){
    52 #ifndef ONLINE_JUDGE
    53     freopen("A.in","r",stdin);
    54     freopen("A.out","w",stdout);
    55 #endif
    56     n=getint(); t=getint();
    57     int x;
    58     F(i,1,t){
    59         x=getint();
    60         F(j,1,x){
    61             a[++tot].v=i;
    62             a[tot].pos=getint();
    63         }
    64     }
    65     sort(a+1,a+n+1,cmp);
    66     int l=0,r=a[n].pos-a[1].pos,mid,ans=0;
    67     while(l<=r){
    68         mid=l+r>>1;
    69         if (check(mid)) ans=mid,r=mid-1;
    70         else l=mid+1;
    71     }
    72     printf("%d
    ",ans);
    73     return 0;
    74 }
    75 
    View Code

    1293: [SCOI2009]生日礼物

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 1204  Solved: 655
    [Submit][Status][Discuss]

    Description

    小西有一条很长的彩带,彩带上挂着各式各样的彩珠。已知彩珠有N个,分为K种。简单的说,可以将彩带考虑为x轴,每一个彩珠有一个对应的坐标(即位置)。某些坐标上可以没有彩珠,但多个彩珠也可以出现在同一个位置上。 小布生日快到了,于是小西打算剪一段彩带送给小布。为了让礼物彩带足够漂亮,小西希望这一段彩带中能包含所有种类的彩珠。同时,为了方便,小西希望这段彩带尽可能短,你能帮助小西计算这个最短的长度么?彩带的长度即为彩带开始位置到结束位置的位置差。

    Input

    第一行包含两个整数N, K,分别表示彩珠的总数以及种类数。接下来K行,每行第一个数为Ti,表示第i种彩珠的数目。接下来按升序给出Ti个非负整数,为这Ti个彩珠分别出现的位置。

    Output

    应包含一行,为最短彩带长度。

    Sample Input

    6 3
    1 5
    2 1 7
    3 1 3 8

    Sample Output

    3

    HINT

    有多种方案可选,其中比较短的是1~5和5~8。后者长度为3最短。
    【数据规模】
    对于50%的数据, N≤10000;
    对于80%的数据, N≤800000;
    对于100%的数据,1≤N≤1000000,1≤K≤60,0≤彩珠位置<2^31。

    Source

    [Submit][Status][Discuss]
  • 相关阅读:
    33.数组声明方式(var构造函数) 、检测数组类型、数组的属性(封装好的就一个length)、数组的方法
    31.this指向(写出调用链,找最近对象) this的默认绑定 隐式绑定 显示绑定(call(绑定对象) apply(绑定对象) 当括号内没放绑定对象的时候恢复默认绑定) bind
    31.
    30.函数作用域链 (GO AO 也叫词法作用域链)、 调用栈、调用栈涉及this绑定
    29.包装类(构造函数) 包装类作用及调用栈
    916. Word Subsets
    246. Strobogrammatic Number
    445. Add Two Numbers II
    2. Add Two Numbers
    341. Flatten Nested List Iterator
  • 原文地址:https://www.cnblogs.com/Tunix/p/4435985.html
Copyright © 2011-2022 走看看