zoukankan      html  css  js  c++  java
  • 【USACO13JAN】牛的阵容Cow Lineup

    原题:

    首先贪一波,k种血统当然是尽可能删光啦

    那么不考虑k种用不完的情况,答案对应的连续血统组成的区间一定是一个包含k+1种血统的区间

    进一步需要发现,在所有的包含k+1种血统的区间中,只需考虑极大区间

    即左右端点延申一格就由k+1变为k+2的区间

    这个性质也易证

    那么我们就可以用双指针,当右端点加入一个血统后,左端点向右移动直到区间内血统数小于k+2

    即枚举右端点,然后考虑左端点最远能到哪里

    接下来就是如何统计这些区间种数量最多的血统

    一种方法是用权值线段树,或平衡树维护

    但是其实还有性质可以挖掘

    即没有必要统计数量最多的血统

    只需将被枚举的右端点的血统的数量统计到答案即可

    虽然极大的含k+1种的区间右端点不一定是数量最多的,但一定存在以数量最多的血统作为右端点的极大子区间

    如果存在最多+非最多的情况,那么把右端的非最多删去,答案不会减少,甚至还可能增加(因为左端点可能还能再向左移动)

    而枚举右端点的时候是逐个枚举的

    所以只将右端点的数量统计保证不会遗漏答案

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 using namespace std;
     5 int n,m,a[110000];
     6 int b[110000],c[110000],ctp=0;
     7 int cnt[110000],nm=0;
     8 int bnrsch(int x){
     9     int l=1,r=ctp,md;
    10     while(l+1<r){
    11         md=(l+r)>>1;
    12         (c[md]<x ? l : r)=md;
    13     }
    14     return c[l]==x ? l : r;
    15 }
    16 int main(){
    17     cin>>n>>m;
    18     for(int i=1;i<=n;++i){
    19         scanf("%d",&a[i]);
    20         b[i]=a[i];
    21     }
    22     sort(b+1,b+n+1);
    23     b[0]=-1;
    24     for(int i=1;i<=n;++i)if(b[i]!=b[i-1])  c[++ctp]=b[i];
    25     for(int i=1;i<=n;++i)  a[i]=bnrsch(a[i]);
    26     int ans=0;
    27     for(int i=1,j=1;i<=n;++i){
    28         ++cnt[a[i]];
    29         if(cnt[a[i]]==1)  ++nm;
    30         for(;nm>m+1;++j){
    31             --cnt[a[j]];
    32             if(!cnt[a[j]])  --nm;
    33         }
    34         ans=max(ans,cnt[a[i]]);
    35         //cout<<j<<" "<<i<<endl;
    36     }
    37     cout<<ans<<endl;
    38     return 0;
    39 }
    View Code
  • 相关阅读:
    浅谈P2P
    一串字符的解密
    下载地址解密
    初探DirectX
    本文介绍在VC 6.0中编译和使用OpenSSL的过程
    鱼钩绑线视频
    PKCS cer 证书
    02、创建顶点缓冲
    [原]SSL 开发简述(Delphi)
    [转]Delphi和C++数据类型对照表
  • 原文地址:https://www.cnblogs.com/cdcq/p/12153599.html
Copyright © 2011-2022 走看看