codeforces 743E

题解:

考虑这个每个数字少个数是可二分的(答案关于个数单调)

然后我们dp

dp[i][S]表示到第i个数,已选完的数字集合为S

转移是贪心取连续一段

预处理转移右端点可以降下复杂度

 1 #include<bits/stdc++.h>
 2 #define maxn 1005
 3 using namespace std;
 4 int n,m;
 5 int a[maxn],c[9];
 6 int dp[maxn][260];
 7 int f[9][maxn][130];
 8 void init()
 9 {
10     for(int x=1;x<=8;++x)
11     {
12         for(int l=0;l<=n;++l)
13         {
14             int cnt=0;
15             f[x][l][0]=l;
16             for(int r=l+1;r<=n;++r)
17             {
18                 if(a[r]==x)
19                 {
20                     ++cnt;
21                     f[x][l][cnt]=r;
22                 }
23             }
24             for(int i=cnt+1;i<=m;++i)f[x][l][i]=n+1;
25         }
26     }
27 }
28 int ans=0;
29 bool check(int L)
30 {
31     memset(dp,128,sizeof(dp));
32     dp[0][0]=0;
33     for(int i=0;i<n;++i)
34     {
35         for(int S=0;S<(1<<8);++S)if(dp[i][S]>=0)
36         {
37             dp[i+1][S]=max(dp[i+1][S],dp[i][S]);
38             for(int k=1;k<=8;++k)if(!(S&(1<<(k-1))))
39             {
40                 int sta=S|(1<<(k-1));
41                 dp[f[k][i][L]][sta]=max(dp[f[k][i][L]][sta],dp[i][S]+L);
42                 dp[f[k][i][L+1]][sta]=max(dp[f[k][i][L+1]][sta],dp[i][S]+L+1);
43             }
44         }
45     }
46     ans=max(ans,dp[n][(1<<8)-1]);
47     if(dp[n][(1<<8)-1]>=0)return 1;
48     else return 0;
49 }
50 int main()
51 {
52     scanf("%d",&n);
53     for(int i=1;i<=n;++i)scanf("%d",&a[i]),c[a[i]]++;
54     m=n;
55     for(int i=1;i<=8;++i)m=min(m,c[i]);
56     m++;
57     init();
58     int l=0,r=m-1;
59     while(l<=r)
60     {
61         int mid=(l+r)>>1;
62         if(check(mid))l=mid+1;
63         else r=mid-1;
64     }
65     printf("%d\n",ans);
66     return 0;
67 }
View Code

 

posted @ 2019-03-30 00:51  幽蝶  阅读(162)  评论(0编辑  收藏  举报