1. 程式人生 > >Educational Codeforces Round 55 E 分治

Educational Codeforces Round 55 E 分治

題意:一個數組,選一個連續區間[L,R] 使得 區間內相同的數 + 區間外a[i]=c的個數最多

思路:似乎可以o(n),這裡提供一個O(nogn)的分治方法,這類只選一個區間的問題很容易想到分治法,難在如何合併左右區間,這裡我們貪心合併即可,維護一下 左右可並的每種a[i] 的最優答案。可能表述不清,詳細見程式碼。

程式碼:

#include<bits/stdc++.h>
#define PB push_back
#define X first
#define Y second
#define FIO std::ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
typedef long long ll;
typedef double LD;
typedef pair<int,int> pii;
const int maxn=5e5+10;
const ll inf=1e9+7;
ll t,n,m,x,y,b,c;
int a[maxn];
struct P{
    int c_cnt=0,res=0;
};
P ans[maxn*4];
int LM[maxn];
int Lbest[maxn],Rbest[maxn];
int solve(int L,int R,int rt,int flag){
    int mid=(L+R)/2;
    if(L==R){
        ans[rt].c_cnt=(a[L]==c);
        return ans[rt].res=1;
    }
    solve(L,mid,rt*2,2);
    solve(mid+1,R,rt*2+1,1);
    ans[rt].res=ans[rt*2].c_cnt+ans[rt*2+1].c_cnt;
    ans[rt].res=max(ans[rt].res,ans[rt*2].res+ans[rt*2+1].c_cnt);
    ans[rt].res=max(ans[rt].res,ans[rt*2+1].res+ans[rt*2].c_cnt);
    ans[rt].c_cnt=ans[rt*2].c_cnt+ans[rt*2+1].c_cnt;
    int tmpc=0;
    for(int i=L;i<=R;++i)LM[a[i]]=Lbest[a[i]]=0;
    for(int i=mid+1;i<=R;++i){
        if(a[i]==c) tmpc++;
        LM[a[i]]++;
        if(LM[a[i]]+ans[rt*2+1].c_cnt-tmpc>Lbest[a[i]])
            Lbest[a[i]]=LM[a[i]]+ans[rt*2+1].c_cnt-tmpc;
    }
    for(int i=L;i<=R;++i)LM[a[i]]=Rbest[a[i]]=0;
    tmpc=0;
    for(int i=mid;i>=L;--i){
        if(a[i]==c) tmpc++;
        LM[a[i]]++;
        if(LM[a[i]]+ans[rt*2].c_cnt-tmpc>Rbest[a[i]]){
            Rbest[a[i]]=LM[a[i]]+ans[rt*2].c_cnt-tmpc;
            ans[rt].res=max(ans[rt].res,Rbest[a[i]]+Lbest[a[i]]);
        }
    }
    return ans[rt].res;
}

int main(){
    FIO;
    cin>>n>>c;
    for(int i=1;i<=n;i++)cin>>a[i];
    cout<<solve(1,n,1,0)<<endl;
	return 0;
}