1. 程式人生 > >【牛客練習賽3-E.絕對半徑2051】 二分+預處理

【牛客練習賽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;
}