codeforces 1335E2 Three Blocks Palindrome (hard version) 枚举+思维

32 篇文章 0 订阅

https://vjudge.net/problem/CodeForces-1335E2
在这里插入图片描述在这里插入图片描述
题目大意:给一个数组,要你找到一个最长的子序列,使得它满足以下形式,其中 a a a b b b可以相等。 x 、 y > = 0 x、y>=0 xy>=0
在这里插入图片描述
思路:我们把这三段命名为左中右,通过枚举左边这一段的结束位置就可以计算出正确答案。假设当前枚举的位置是 i i i,那么 [ 1 … i ] [1…i] [1i]这段子序列应该取什么颜色呢?其实取 a [ i ] a[i] a[i]就可以了,因为其它的颜色要么在 [ 1 … i − 1 ] [1…i-1] [1i1]枚举过了,要么还没出现。那么知道了左边这一段的颜色,而右边这一段的颜色和左边是相等的且出现的次数要一致,假设在区间 [ y + 1 … n ] [y+1…n] [y+1n]内颜色 a [ i ] a[i] a[i]也出现了相同的次数,不妨设为 c t ct ct,此时留给中间段的区间只剩下 [ i + 1 , y ] [i+1,y] [i+1,y]了,那么我们可以枚举所有的颜色,取在这段区间中出现次数最多的那种,不妨设为 M A X MAX MAX,那么这种情况下的最佳结果就是 2 ∗ c t + M A X 2*ct+MAX 2ct+MAX。现在问题就是如何在已知 a [ i ] 、 c t a[i]、ct a[i]ct的情况下,求出这个 y y y。我们可以搞一个 c o l r [ c o l o r _ n u m ] [ n ] colr[color\_num][n] colr[color_num][n],用 c o l r [ i ] [ j ] colr[i][j] colr[i][j]表示颜色 i i i倒数第 j j j次出现的位置,显然这个数组可以 O ( n ) O(n) O(n)预处理出来,而且可以在 O ( 1 ) O(1) O(1)内得到 y y y。那么问题就解决了,总复杂度 O ( n ∗ c o l o r _ n u m ) O(n*color\_num) O(ncolor_num)

#include<bits/stdc++.h>
#define INF 0x3f3f3f3f
#define eps 1e-8
#define pr pair<int,int>
using namespace std;
typedef long long ll;

const int maxn=2e5+5;
const int num=200;

int t,n;
int a[maxn],cnt[maxn][205];
vector<int> colr[205];

int main()
{
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            for(int j=1;j<=num;j++)
                cnt[i][j]=cnt[i-1][j];
            ++cnt[i][a[i]];
        }
        for(int i=n;i>=1;i--)
            colr[a[i]].push_back(i);
        int ans=0,MAX,y,color,ct;
        for(int i=1;i<=n;i++)
        {
            ct=cnt[i][a[i]];
            ans=max(ans,ct);
            color=a[i];
            if(colr[color].size()<ct)
                continue;
            y=colr[color][ct-1]-1;
            if(y<i+1)
                continue;
            MAX=0;
            for(int k=1;k<=num;k++) //中间部分的区间为 [i+1,y]
                MAX=max(MAX,cnt[y][k]-cnt[i][k]);
            ans=max(ans,ct*2+MAX);
        }
        printf("%d\n",ans);
        for(int i=1;i<=num;i++)
            colr[i].clear();
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值