zoukankan      html  css  js  c++  java
  • [codeforces743E]Vladik and cards

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

    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 exceeding 8 — 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.

    题解:

    先简单翻译一下,给一个序列,求最长的满足下面条件的子序列:

    第一,相同数字连续;第二,每种数字出现次数之差不超过1

    我们来考虑,由于每种数字出现都是连续的,因此一种数字一旦出现过,就不能再出现第二次。

    所以我们可以用二进制来压每种数字是否出现过。

    那么,每种数字出现次数的限制怎么处理?

    这个东西不好说,所以我们考虑,如果有一种选择,使得每种数字都出现了至少a次,

    那么一定会有其他选择,使得每种数字都出现了至少a-1次,a-2次……1次。

    因此,我们就可以二分了!二分枚举每种数字至少出现的次数len,那么每种数字要么出现len次,要么出现len+1次。

    对于某个len,定义状态数组f[i][j]为前i位中,数字出现状态为j时出现len+1次的数的最大种数

    设tmp=max{f[i][(1<<8)-1}},那么显然,ans=tmp*(len+1)+(8-tmp)*len

    在选取新的数字时,新数字要么出现len次,要么出现len+1次,

    那么状态方程也显而易见了(刷表),更新对应位置的f值即可

    最后注意特判:如果二分得到len=0,那么ans=出现的数的种数

    代码见下:

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<vector>
     4 #include<algorithm>
     5 using namespace std;
     6 const int N=1010;
     7 const int K=(1<<8)+10;
     8 int n,a[N],f[N][K],now[10],bit[15];//now数组用来记录转移位置 
     9 inline int max(int a,int b){return a>b?a:b;}
    10 vector<int> loc[10];
    11 inline int judge(int len)
    12 {
    13     for(int i=1;i<=8;i++)now[i]=0;
    14     memset(f,0xaf,sizeof(f));
    15     int inf=f[0][0];
    16     f[0][0]=0;
    17     for(int i=0;i<n;i++)
    18     {
    19         for(int j=0;j<bit[8];j++)
    20         {
    21             if(f[i][j]==inf)continue;
    22             for(int k=0;k<8;k++)
    23             {
    24                 if(j&bit[k])continue;
    25                 int pos=now[k+1]+len-1;
    26                 if(pos>=loc[k+1].size())continue;
    27                 f[loc[k+1][pos]][j|bit[k]]=max(f[loc[k+1][pos]][j|bit[k]],f[i][j]);
    28                 pos++;
    29                 if(pos>=loc[k+1].size())continue;
    30                 f[loc[k+1][pos]][j|bit[k]]=max(f[loc[k+1][pos]][j|bit[k]],f[i][j]+1);
    31             }
    32         }
    33         now[a[i]]++;
    34     }
    35     int ans=inf;
    36     for(int i=0;i<=n;i++)
    37         ans=max(ans,f[i][bit[8]-1]);
    38     if(ans==inf)return -1;
    39     return ans*(len+1)+(8-ans)*len;
    40 }
    41 int main()
    42 {
    43     bit[0]=1;for(int i=1;i<=10;i++)bit[i]=bit[i-1]<<1;
    44     scanf("%d",&n);
    45     for(int i=1;i<=n;i++)
    46         scanf("%d",&a[i]),loc[a[i]].push_back(i);
    47     int l=0,r=n/8+1,ans=2333;
    48     while(l<=r)
    49     {
    50         int mi=(l+r)>>1;
    51         if(judge(mi)!=-1)ans=judge(mi),l=mi+1;
    52         else r=mi-1;
    53      }
    54      if(ans==2333)
    55      {
    56         ans=0;
    57          for(int i=1;i<=8;i++)
    58              if(!loc[i].empty())ans++;
    59     }
    60     printf("%d",ans);
    61 }
    codeforces743E
  • 相关阅读:
    图片一句话木马简单制作方法
    kali各工具使用介绍
    隐写工具zsteg安装及使用教程
    内网渗透中mimikatz的使用
    kali meterpreter中mimikatz模块获取密码
    一个恐怖份子上传了这张照片到社交网络。里面藏了什么信息?
    攻防世界MISC进阶之签到题
    EMC存储重装系统分区丢失恢复方法
    服务器数据迁移方法
    教您分辨U盘不能识别是哪儿坏了
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7106130.html
Copyright © 2011-2022 走看看