Vladik was bored on his way home and decided to play the following game. He took n cards and put them in a row in front of himself. Every card has a positive integer number not exceeding 8 written on it. He decided to find the longest subsequence of cards which satisfies the following conditions:
- the number of occurrences of each number from 1 to 8 in the subsequence doesn't differ by more then 1 from the number of occurrences of any other number. Formally, if there are ck cards with number k on them in the subsequence, than for all pairs of integers the condition |ci - cj| ≤ 1 must hold.
- if there is at least one card with number x on it in the subsequence, then all cards with number x in this subsequence must form a continuous segment in it (but not necessarily a continuous segment in the original sequence). For example, the subsequence [1, 1, 2, 2] satisfies this condition while the subsequence [1, 2, 2, 1] doesn't. Note that [1, 1, 2, 2] doesn't satisfy the first condition.
Please help Vladik to find the length of the longest subsequence that satisfies both conditions.
The first line contains single integer n (1 ≤ n ≤ 1000) — the number of cards in Vladik's sequence.
The second line contains the sequence of n positive integers not exceeding 8 — the description of Vladik's sequence.
Print single integer — the length of the longest subsequence of Vladik's sequence that satisfies both conditions.
3 1 1 1
1
8 8 7 6 5 4 3 2 1
8
24 1 8 1 2 8 2 3 8 3 4 8 4 5 8 5 6 8 6 7 8 7 8 8 8
17
In the first sample all the numbers written on the cards are equal, so you can't take more than one card, otherwise you'll violate the first condition.
题意
给定一个序列an,序列中只有1~8的8个整数,让你选出一个子序列,满足下列两个要求
1.不同整数出现的次数相差小于或等于1
2.子序列中整数分布是连续的,即子序列的整数必须是1,1,1....1,2,2,2.....2,2.......连续分布,可以是任意顺序而不要求递增,比如312587644
题解:
首先我们可以二分整数出现的次数,假如说二分出现次数是l,那么是指有些出现l次,而另一些出现l+1次(l越大越优)
由于每个整数只有两种状态,要么选l个,要么选l+1个。
而且选l+1个的个数越多越好。
那么可以将d[i][j]状态定义为选完前i个中状态已经为j(记录已经选了哪些整数种类)时出现次数为l+1的整数的最大个数。
枚举对第k个整数做决策,dp[i][s]就可以转移到另外两个状态
dp[next(i, l)][j|(1<<a[i])] = max(itself, dp[i][j]);
dp[next(i, l+1)][j|(1<<a[i])] = max(itself, dp[i][j]+1);
其中next(i, l)是指从i开始,往后的第l个a[i]的整数位置
然后取dp[1~n][(1<<8)-1]中的最大值,返回答案即可
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
#include<stack>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define fi first
#define se second
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const int inf=0x3fffffff;
const ll mod=1000000007;
const int maxn=1000+100;
int a[maxn];
VI nex[10];
int d[maxn][(1<<8)+100];
int ans;
int n;
int ne[maxn][maxn];
int solve(int l)
{
for(int i=0;i<=n;i++) for(int j=0;j<(1<<8);j++) d[i][j]=-inf;
d[0][0]=0;
int res=-inf; //res表示长度为l+1的最大数目
for(int i=1;i<=n;i++)
{
for(int j=0;j<(1<<8);j++)
{
d[i][j]=max(d[i][j],d[i-1][j]);//注意这个,因为d[i][j]指的是到第i个为止,是前i个的情况,而不是以i结尾
if(j&(1<<a[i])) continue;
if(ne[i][l]!=-1)
d[ne[i][l]][j|(1<<a[i])]=max(d[ne[i][l]][j|(1<<a[i])],d[i-1][j]);
if(ne[i][l+1]!=-1)
d[ne[i][l+1]][j|(1<<a[i])]=max(d[ne[i][l+1]][j|(1<<a[i])],d[i-1][j]+1);
}
}
if(!l) //长度为0时特判一下,因为此时最终状态j可能不是(1<<8)-1
{
for(int i=1;i<=n;i++)
for(int j=0;j<(1<<8);j++)
res=max(res,d[i][j]);
}
else
{
for(int i=1;i<=n;i++)
res=max(res,d[i][(1<<8)-1]);
}
if(res<0) return -1;
return res*(l+1)+(8-res)*l;
}
int main()
{
scanf("%d",&n);
rep(i,1,n+1)
{
scanf("%d",&a[i]);
a[i]--;
nex[a[i]].pb(i);
}
memset(ne,-1,sizeof(ne));
for(int i=0;i<8;i++)
{
for(int j=0;j<nex[i].size();j++)
{
for(int k=j;k<nex[i].size();k++)
{
ne[nex[i][j]][k-j+1]=nex[i][k]; //ne数组保存第i个位置的和a[i]值相等的下k个位置,注意d[a[i]][1]=i
}
}
}
int l=0,r=n/8+1;
ans=-1;
while(l<=r)
{
int m=(l+r)/2;
int t=solve(m);
if(t!=-1)
{
ans=max(ans,t);
l=m+1;
}
else r=m-1;
}
printf("%d\n",ans);
return 0;
}