思路:这题不看题解一点思路都没有。解法是这样的,满足条件的序列必定是有a种数的个数为x,8-a种数的个数为x+1,我们二分这个x,用状压dp判断是否满足有满足条件的,然后记录答案就可以了。状压dp的思路是这样的,首先预处理处每种数字第k次出现的位置。dp[i][j]表示终点为i,状态为j的出现(x+1)次的数的种类有几个,很容易得出转移方程,详情看代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
#define inf 0x3f3f3f3f3f3f3f3f
const int maxn=1005;
vector<int>v[15];
int n,a[maxn];
int dp[maxn][(1<<8)+5];
int solve(int x){
memset(dp,-1,sizeof(dp));
dp[0][0]=0;
int now[15]={0};
for(int i=0;i<=n;i++){
now[a[i]]++;
for(int j=0;j<(1<<8);j++){
if(~dp[i][j]){
for(int k=0;k<8;k++){
if((j&(1<<k))||v[k+1].size()-now[k+1]<x)
continue;
int nextstatus=j|(1<<k);
int nextindex=i;
if(now[k+1]+x-1>=0)
nextindex=nextindex=v[k+1][now[k+1]+x-1];
dp[nextindex][nextstatus]=max(dp[nextindex][nextstatus],dp[i][j]);
if(v[k+1].size()-now[k+1]>=x+1){
nextindex=v[k+1][now[k+1]+x];
dp[nextindex][nextstatus]=max(dp[nextindex][nextstatus],dp[i][j]+1);
}
}
}
}
}
int ans=-1;
for(int i=1;i<=n;i++){
ans=max(ans,dp[i][(1<<8)-1]);
}
if(~ans)
return ans*(x+1)+(8-ans)*x;
else
return ans;
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
v[a[i]].push_back(i);
}
int l=0,r=n;
int ans;
while(l<=r){
int mid=l+r>>1;
int now=solve(mid);
if(now>0){
ans=now;
l=mid+1;
}
else
r=mid-1;
}
printf("%d\n",ans);
}