Three Blocks Palindrome

E2 - Three Blocks Palindrome (hard version)

参考:Codeforces Round #634 (Div. 3) Editorial

这道题考的主要是前缀和,用sum[i][j]保存到第 i 个数 j 出现的总次数。

关键代码在这一块,首先遍历两边要取的数字是什么,然后确定两边要取的数字的个数,以便确定边界(l,r),然后遍历中间应该取什么数,并且根据 l 和 r 的范围确定该数的个数,最后贪心即可。

for(int mid=1;mid<=200;++mid){
    ans=max(ans,int(pos[mid].size()));
    for(int side=0; side<pos[mid].size()/2; ++side){
        int l=pos[mid][side]+1,r=pos[mid][pos[mid].size()-side-1]-1;
        for(int val=1;val<=200;++val){
            int sum=sum[r][val]-sum[l-1][val];
            ans=max(ans, (side+1)*2+sum);
        }
    }
}

该题关键点在于,将遍历的重点从 n 转移到了a[i]的取值范围来,从而将复杂度降低。

// Created by CAD on 2020/4/15.
#include <bits/stdc++.h>
using namespace std;

const int maxn=2e5+5;
int sum[maxn][205];
int a[maxn];
int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    int t;cin>>t;
    while(t--){
        int n;cin>>n;
        for(int i=1;i<=n;++i)
            cin>>a[i];
        vector<int> pos[201];
        for(int i=1;i<=n;++i){
            for(int j=1;j<=200;++j) sum[i][j]=sum[i-1][j];
            sum[i][a[i]]++;
            pos[a[i]].push_back(i);
        }
        int ans=0;
        for(int mid=1;mid<=200;++mid){
            ans=max(ans,int(pos[mid].size()));
            for(int side=0; side<pos[mid].size()/2; ++side){
                int l=pos[mid][side]+1,r=pos[mid][pos[mid].size()-side-1]-1;
                for(int val=1;val<=200;++val){
                    int sum=sum[r][val]-sum[l-1][val];
                    ans=max(ans, (side+1)*2+sum);
                }
            }
        }
        cout<<ans<<"\n";
    }
    return 0;
}
posted @ 2020-04-15 21:39  caoanda  阅读(184)  评论(0编辑  收藏  举报