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
  • 相关阅读:
    linux挂载
    kafka
    使用python27+flask
    arcpy 10.8计算最短路径,并复制出结果
    arcgis pro2.5使用试用
    arcgis engine create featureclass , gp工具
    python和c#的 opencv文字区域识别
    C#调用带参数并输出控制台的python的EXE程序
    arcgis10.8中 python27打包exe文件
    arcgis engine指定范围导出屏幕图片
  • 原文地址:https://www.cnblogs.com/LadyLex/p/7106130.html
Copyright © 2011-2022 走看看