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