【牛客练习赛3-E.绝对半径2051】 二分+预处理

E题

给 你 一 个 长 度 为 n 的 数 组 , 最 多 删 除 k 个 元 素 , 求 最 长 相 同 连 续 子 序 列 。 给你一个长度为n的数组,最多删除k个元素,求最长相同连续子序列。 nk
0 &lt; = k &lt; = n &lt; = 1 ∗ 1 0 5 1 &lt; = a [ i ] &lt; = 1 ∗ 1 0 9 0&lt;=k&lt;=n&lt;=1*10^{5} \quad \quad 1&lt;=a[i]&lt;=1*10^{9} 0<=k<=n<=11051<=a[i]<=1109
本 题 由 于 数 据 范 围 是 1 e 5 , 所 以 肯 定 是 本题由于数据范围是1e5,所以肯定是 1e5,nlogn 的 做 法 的做法
考 虑 到 最 长 相 同 子 序 列 肯 定 是 同 一 种 元 素 构 成 的 考虑到最长相同子序列肯定是同一种元素构成的
所 以 我 们 可 以 对 每 个 元 素 检 验 可 构 成 的 最 长 连 续 子 序 列 。 所以我们可以对每个元素检验可构成的最长连续子序列。
我 们 可 以 枚 举 右 端 点 , 然 后 二 分 左 端 点 , 如 果 删 除 k 个 点 能 达 到 长 度 为 l 我们可以枚举右端点,然后二分左端点,如果删除k个点能达到长度为l kl
删 除 k 个 点 肯 定 能 达 到 删除k个点肯定能达到 kl’<l , 所 以 答 案 是 可 以 二 分 的 , ,所以答案是可以二分的,
所 以 我 们 只 要 枚 举 右 端 点 + 验 证 就 好 了 , 所以我们只要枚举右端点+验证就好了, +
要 提 前 预 处 理 每 个 数 到 达 某 个 位 置 的 总 个 数 , 要提前预处理每个数到达某个位置的总个数,
二 分 条 件 为 ( l − r 之 间 的 a [ i ] 的 个 数 + k ) &gt; = ( r − l + 1 ) . 二分条件为(l-r之间的a[i]的个数+k)&gt;=(r-l+1). (lra[i]+k)>=(rl+1).
E题代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
const int maxn = 1e5+5;
#define dbg(x) cout<<#x<<" :"<<x<<endl;
int a[maxn];
map<int,vector<int> > mm;
map<int,int> pre;
map<pair<int,int>,int> sum;
int main()
{
    int n,k;
    int ans=0;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(int i=1;i<=n;i++) mm[a[i]].push_back(i);
    for(int i=1;i<=n;i++)
    {
        sum[pair<int,int>(a[i],i)]=sum[pair<int,int>(a[i],pre[a[i]])]+1;
        pre[a[i]]=i;
    }
    map<int,vector<int> >::iterator it;
    for(it=mm.begin();it!=mm.end();++it)
    {
        int tmp=it->first;
        int sz=(it->second).size();
        if(sz<=1) continue;
        for(int i=0;i<sz;i++)
        {
            int l=0,r=i,mid;
            int rr=mm[tmp][i];
            while(l<=r)
            {
                mid=(l+r)>>1;
                if((rr-mm[tmp][mid]+1)-(sum[pair<int,int>(tmp,rr)]-sum[pair<int,int>(tmp,mm[tmp][mid])]+1)<=k) r=mid-1;
                else l=mid+1;
            }
            ans=max(ans,sum[pair<int,int>(tmp,mm[tmp][i])]-sum[pair<int,int>(tmp,mm[tmp][l])]+1);
        }
    }
    printf("%d\n",ans);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值