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

E题

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

猜你喜欢

转载自blog.csdn.net/qq_38891827/article/details/84064532