codeforces 743E
题解:
考虑这个每个数字少个数是可二分的(答案关于个数单调)
然后我们dp
dp[i][S]表示到第i个数,已选完的数字集合为S
转移是贪心取连续一段
预处理转移右端点可以降下复杂度
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
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 }