Codeforces Round #384 (Div. 2)E(状压dp+二分,好题)
来源:互联网 发布:淘宝网的性用品有用吗 编辑:程序博客网 时间:2024/04/28 20:02
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.
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.
Print single integer — the length of the longest subsequence of Vladik's sequence that satisfies both conditions.
31 1 1
1
88 7 6 5 4 3 2 1
8
241 8 1 2 8 2 3 8 3 4 8 4 5 8 5 6 8 6 7 8 7 8 8 8
17
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.
题意
给定一个序列an,序列中只有1~8的8个整数,让你选出一个子序列,满足下列两个要求
1.不同整数出现的次数相差小于或等于1
2.子序列中整数分布是连续的,即子序列的整数必须是1,1,1....1,2,2,2.....2,2.......连续分布,可以是任意顺序而不要求递增,比如312587644
题解:
首先我们可以二分整数出现的次数,假如说二分出现次数是l,那么是指有些出现l次,而另一些出现l+1次(l越大越优)
由于每个整数只有两种状态,要么选l个,要么选l+1个。
而且选l+1个的个数越多越好。
那么可以将d[i][j]状态定义为选完前i个中状态已经为j(记录已经选了哪些整数种类)时出现次数为l+1的整数的最大个数。
枚举对第k个整数做决策,dp[i][s]就可以转移到另外两个状态
dp[next(i, l)][j|(1<<a[i])] = max(itself, dp[i][j]);
dp[next(i, l+1)][j|(1<<a[i])] = max(itself, dp[i][j]+1);
其中next(i, l)是指从i开始,往后的第l个a[i]的整数位置
然后取dp[1~n][(1<<8)-1]中的最大值,返回答案即可
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<queue>#include<stack>using namespace std;#define rep(i,a,n) for (int i=a;i<n;i++)#define per(i,a,n) for (int i=n-1;i>=a;i--)#define pb push_back#define fi first#define se secondtypedef vector<int> VI;typedef long long ll;typedef pair<int,int> PII;const int inf=0x3fffffff;const ll mod=1000000007;const int maxn=1000+100;int a[maxn];VI nex[10];int d[maxn][(1<<8)+100];int ans;int n;int ne[maxn][maxn];int solve(int l){ for(int i=0;i<=n;i++) for(int j=0;j<(1<<8);j++) d[i][j]=-inf; d[0][0]=0; int res=-inf; //res表示长度为l+1的最大数目 for(int i=1;i<=n;i++) { for(int j=0;j<(1<<8);j++) { d[i][j]=max(d[i][j],d[i-1][j]);//注意这个,因为d[i][j]指的是到第i个为止,是前i个的情况,而不是以i结尾 if(j&(1<<a[i])) continue; if(ne[i][l]!=-1) d[ne[i][l]][j|(1<<a[i])]=max(d[ne[i][l]][j|(1<<a[i])],d[i-1][j]); if(ne[i][l+1]!=-1) d[ne[i][l+1]][j|(1<<a[i])]=max(d[ne[i][l+1]][j|(1<<a[i])],d[i-1][j]+1); } } if(!l) //长度为0时特判一下,因为此时最终状态j可能不是(1<<8)-1 { for(int i=1;i<=n;i++) for(int j=0;j<(1<<8);j++) res=max(res,d[i][j]); } else { for(int i=1;i<=n;i++) res=max(res,d[i][(1<<8)-1]); } if(res<0) return -1; return res*(l+1)+(8-res)*l;}int main(){ scanf("%d",&n); rep(i,1,n+1) { scanf("%d",&a[i]); a[i]--; nex[a[i]].pb(i); } memset(ne,-1,sizeof(ne)); for(int i=0;i<8;i++) { for(int j=0;j<nex[i].size();j++) { for(int k=j;k<nex[i].size();k++) { ne[nex[i][j]][k-j+1]=nex[i][k]; //ne数组保存第i个位置的和a[i]值相等的下k个位置,注意d[a[i]][1]=i } } } int l=0,r=n/8+1; ans=-1; while(l<=r) { int m=(l+r)/2; int t=solve(m); if(t!=-1) { ans=max(ans,t); l=m+1; } else r=m-1; } printf("%d\n",ans); return 0;}
- Codeforces Round #384 (Div. 2)E(状压dp+二分,好题)
- E. Vladik and cards Codeforces Round #384 (Div. 2) 好题 二分+(贪心+状态压缩DP)判断
- Codeforces Round #384 (Div. 2)E.Vladik and cards【二分+状压dp】
- Codeforces Round #384 (Div. 2)E.Vladik and cards【二分+状压dp】(未敲)
- Codeforces Round #277.5 (Div. 2) E. Hiking(二分 DP)
- Codeforces Round #383 (Div. 2) E(贪心,二分图染色,好题)
- Codeforces Round #316 (Div. 2)E. Pig and Palindromes(dp好题)
- Codeforces Round #385 (Div. 2) E. Hongcow Buys a Deck of Cards DP+好题
- Codeforces Round #341 (Div. 2)E(矩阵快速幂优化dp,好题)
- Codeforces Round #396 (Div. 2)E(树形dp,按位运算,好题)
- dp+Codeforces Round #274 (Div. 2)E
- 【DP】Codeforces Round #341 (Div. 2) E
- Codeforces Round #316 (Div. 2) E dp
- Codeforces Round #371 (Div. 2) E dp
- Codeforces Round #376 (Div. 2) E dp
- Codeforces Round #302 (Div. 2) E. Remembering Strings(状压dp)
- Codeforces Round #383 (Div. 2)D(dp,好题)
- Codeforces 615E Hexagons (Round #338 (Div. 2) E题) 二分答案+找规律
- [hihocoder1066]无间道之并查集
- C# DataTable的詳細用法
- 【JZOJ 4923】【NOIP2017提高组模拟12.17】巧克力狂欢
- shu营销通外推软件默认标题
- 什么是算法??
- Codeforces Round #384 (Div. 2)E(状压dp+二分,好题)
- python集合常用方法
- 机房收费系统——对象变量或with块变量未设置
- ubuntu安装nginx
- java选修复习随
- 三星手机拍照强制切换到横屏及照片旋转问题
- Linux C Socket常用函数详解
- 【C#】—数组
- Spring Boot+mybatis+thymeleaf集成通用mapper分页查询