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

来源:互联网 发布:log4j数据存进mongodb 编辑:程序博客网 时间:2024/05/01 23:50

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 then1 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
31 1 1
Output
1
Input
88 7 6 5 4 3 2 1
Output
8
Input
241 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);    }}





0 0
原创粉丝点击