您的位置:首页 > 其它

Codeforces Round #384 (Div. 2)E.Vladik and cards【二分+状压dp】

2016-12-16 17:17 302 查看
E. Vladik and cards

time limit per test
2 seconds

memory limit per test
256 megabytes

input
standard input

output
standard output

Vladik was bored on his way home and decided to play the following game. He tookn cards and put them in a row in front of himself. Every card has a positive integer number not exceeding8
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 to8 in the subsequence doesn't differ by more then
1 from the number of occurrences of any other number. Formally, if there areck cards with numberk 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 numberx 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.

Input
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 exceeding8 — the description of Vladik's sequence.

Output
Print single integer — the length of the longest subsequence of Vladik's sequence that satisfies both conditions.

Examples

Input
3
1 1 1


Output
1


Input
8
8 7 6 5 4 3 2 1


Output
8


Input
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


Output
17


Note
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.

题目大意:

给你一个长度为N的一个序列,需要我们找到一个最长的序列,保证每个元素(1~8)的个数之前的绝对值差小于等于1,而且对应选出来的序列中,需要保证相同的元素是连续的。

思路(补题真好玩系列0.0):思路来源于(http://www.cnblogs.com/Saurus/p/6183721.html);

1、首先我们很容易想到状压,我们肯定是状压8个数字的状态,其中1表示这个位子上的数已经选完了,0表示没有选完,那么我们在想dp数组的维度的时候,以及初算时间复杂度的时候,发现这个出现的次数一直是一个很难处理的点,那么我们首先对这个出现的次数进行优化:

①我们可以通过枚举来dp,每次枚举一个出现的次数,进行最大值的维护 ,我们不难想到:对应这个出现的次数越多,结果就可能越长,那么其具有单调性。

②对于可以枚举的具有单调性存在的变量,我们可以通过二分查找来进行优化。

2、那么我们每一次二分枚举出的当前值mid,表示本次二分枚举出来每个数将要出现的次数。

①对于当前值mid,每种数字出现的次数要么是mid次,要么是mid-1次。

②考虑dp,我们设定dp【i】【j】表示dp过程进行到第i位,对应j状态下的最多出现mid次的数字的个数。

③那么考虑状态转移方程:

如果我们直接暴力的话肯定时间复杂度是吃不消的,那么我们考虑调用一个vector<int >mp;mp【i】用于存储数字i出现的各个位子,我们按照升序排列存储。

那么接下来:



④维护好每次二分情况的最大值即可。

Ac代码:

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<vector>
using namespace std;
int a[100050];
int ans,n;
vector<int >mp[1050];
int cur[1050];
int dp[1050][1<<8];
int Slove(int mid)
{
int end=(1<<8);
for(int i=1;i<=8;i++)cur[i]=0;
memset(dp,-1,sizeof(dp));
dp[1][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<end;j++)
{
if(dp[i][j]<0)continue;
for(int k=1;k<=8;k++)
{
if(j &(1<<(k-1)))continue;
if(mp[k].size()-cur[k]<mid-1)continue;
dp[mp[k][cur[k]+mid-2]][j|(1<<(k-1))]=max( dp[mp[k][cur[k]+mid-2]][j+(1<<(k-1))],dp[i][j]);
if(mp[k].size()-cur[k]<mid)continue;
dp[mp[k][cur[k]+mid-1]][j|(1<<(k-1))]=max( dp[mp[k][cur[k]+mid-1]][j+(1<<(k-1))],dp[i][j]+1);
}
}
cur[a[i]]++;
}
int sum=-0x3f3f3f3f;
for(int i=1;i<=n;i++)sum=max(sum,dp[i][(1<<8)-1]);
if(sum<=0)return 0;
ans=max(ans,sum*mid+(8-sum)*(mid-1));
return 1;
}
int main()
{
while(~scanf("%d",&n))
{
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
for(int i=1;i<=n;i++)mp[a[i]].push_back(i);
int l=2,r=n;
ans=0;
while(r-l>=0)
{
int mid=(l+r)/2;
if(Slove(mid)==1)
{
l=mid+1;
}
else r=mid-1;
}
if(ans==0)
{
for(int i=1;i<=8;i++)if(mp[i].size()>0)ans++;
}
printf("%d\n",ans);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Codeforces#384Div. 2