Codeforces Round #634 (Div. 3) E1 E2 Three Blocks Palindrome题解(暴力枚举/枚举优化)

E1题目链接

题目大意

给你一个大小小于2000的数组a,其中1<=a[i]<=26,让你找出满足条件的最长子序列。

条件为:这个子序列满足aba的即前缀和后缀的元素都为一个数,中间的元素都相等即可

题目思路

看到这个数据,可以直接预处理一下前缀和后缀,然后可以直接枚举两个端点,暴力计算即可

代码

#include<iostream>
#include<cstdio>
#include<set>
#include<math.h>
#include<queue>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn=2e3+5;
int a[maxn],t,n,cnt[maxn];
int pre[maxn][30],suf[maxn][30];
int main(){
    scanf("%d",&t);
    while(t--){
        memset(pre,0,sizeof(pre));
        memset(suf,0,sizeof(suf));
        scanf("%d",&n);
        for(int i=1;i<=n;i++){
            //pre[i][j]为[1,i]内j的个数
            scanf("%d",&a[i]);
            for(int j=1;j<=26;j++){
                pre[i][j]=pre[i-1][j]+(j==a[i]);
            }
        }
        for(int i=n;i>=1;i--){
            //suf[i][j]为[i,n]内j的个数
            for(int j=1;j<=26;j++){
                suf[i][j]=suf[i+1][j]+(j==a[i]);
            }
        }
        int ans=1;
        for(int i=1;i<=n;i++){
            for(int j=i+1;j<=n;j++){
                int cntin=0,cntout=0;
                for(int k=1;k<=26;k++){
                    cntin=max(cntin,pre[j-1][k]-pre[i][k]);
                    //[i+1,j-1]内部相等的元素
                    cntout=max(cntout,2*min(pre[i][k],suf[j][k]));
                }
                ans=max(ans,cntin+cntout);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

E2题目链接

题目大意

数组变成2e5的大小,1<=a[i]<=200

题目思路

这个其实还是一个枚举的过程,只不过枚举优化了一点,标记每一个元素的位置。直接枚举前缀和后缀的元素。

代码

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int t,n,a[maxn],pre[maxn][205],ans;
vector<int> pos[205];
void init(){
    ans=0;
    for(int i=1;i<=200;i++){
        pos[i].clear();
    }
}
int main(){
    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        init();
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pos[a[i]].push_back(i);
            for(int j=1;j<=200;j++){
                pre[i][j]=pre[i-1][j]+(j==a[i]);
            }
        }
        for(int i=1;i<=200;i++){
            ans=max(ans,pre[n][i]);
        }
        for(int i=1;i<=200;i++){
            for(int j=1;j<=pos[i].size()/2;j++){
                int l=pos[i][j-1],r=pos[i][pos[i].size()-j];
                int cntin=0;
                for(int k=1;k<=200;k++){
                    cntin=max(cntin,pre[r-1][k]-pre[l][k]);
                }
                ans=max(ans,cntin+j*2);
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}

注意:复杂度从最后哪个嵌套循环看起来是200200n,但是其实不应该那么分析。应该分析所有的pos[i].size()总和最多2e5,所以复杂度其实是200*n

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值