[codeforces743E]Vladik and cards
2 seconds
256 megabytes
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.
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.
3
1 1 1
1
8
8 7 6 5 4 3 2 1
8
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
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.
题解:
先简单翻译一下,给一个序列,求最长的满足下面条件的子序列:
第一,相同数字连续;第二,每种数字出现次数之差不超过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=出现的数的种数
代码见下:
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=;
const int K=(<<)+;
int n,a[N],f[N][K],now[],bit[];//now数组用来记录转移位置
inline int max(int a,int b){return a>b?a:b;}
vector<int> loc[];
inline int judge(int len)
{
for(int i=;i<=;i++)now[i]=;
memset(f,0xaf,sizeof(f));
int inf=f[][];
f[][]=;
for(int i=;i<n;i++)
{
for(int j=;j<bit[];j++)
{
if(f[i][j]==inf)continue;
for(int k=;k<;k++)
{
if(j&bit[k])continue;
int pos=now[k+]+len-;
if(pos>=loc[k+].size())continue;
f[loc[k+][pos]][j|bit[k]]=max(f[loc[k+][pos]][j|bit[k]],f[i][j]);
pos++;
if(pos>=loc[k+].size())continue;
f[loc[k+][pos]][j|bit[k]]=max(f[loc[k+][pos]][j|bit[k]],f[i][j]+);
}
}
now[a[i]]++;
}
int ans=inf;
for(int i=;i<=n;i++)
ans=max(ans,f[i][bit[]-]);
if(ans==inf)return -;
return ans*(len+)+(-ans)*len;
}
int main()
{
bit[]=;for(int i=;i<=;i++)bit[i]=bit[i-]<<;
scanf("%d",&n);
for(int i=;i<=n;i++)
scanf("%d",&a[i]),loc[a[i]].push_back(i);
int l=,r=n/+,ans=;
while(l<=r)
{
int mi=(l+r)>>;
if(judge(mi)!=-)ans=judge(mi),l=mi+;
else r=mi-;
}
if(ans==)
{
ans=;
for(int i=;i<=;i++)
if(!loc[i].empty())ans++;
}
printf("%d",ans);
}
codeforces743E
[codeforces743E]Vladik and cards的更多相关文章
- CodeForces743E. Vladik and cards 二分+状压dp
这个题我们可以想象成_---___-----__的一个水柱它具有一遍优一遍行的性质因此可以用来二分最小值len,而每次二分后我们都要验根,we可以把这个水柱想成我们在每个数段里取前一段的那个数后一段有 ...
- Codeforces Round #384 (Div. 2) 734E Vladik and cards
E. Vladik and cards time limit per test 2 seconds memory limit per test 256 megabytes input standard ...
- Codeforces Round #384 (Div. 2) E. Vladik and cards 状压dp
E. Vladik and cards 题目链接 http://codeforces.com/contest/743/problem/E 题面 Vladik was bored on his way ...
- Vladik and cards
Vladik and cards time limit per test 2 seconds memory limit per test 256 megabytes input standard in ...
- CF384 div2 E. Vladik and cards
题意 给你一个的排列,求一个满足条件的最长子序列 每种数字的差小于等于,并且每种数字之内是连续的 解法 首先单纯认为用肯定不行的 所以应该考虑二分答案(所求长度具有二分性) 再用dp判断是否可行,这个 ...
- Vladik and cards CodeForces - 743E (状压)
大意: 给定序列, 求选出一个最长的子序列, 使得任选两个[1,8]的数字, 在子序列中的出现次数差不超过1, 且子序列中相同数字连续. 正解是状压dp, 先二分转为判断[1,8]出现次数>=x ...
- 【codeforces 743E】Vladik and cards
[题目链接]:http://codeforces.com/problemset/problem/743/E [题意] 给你n个数字; 这些数字都是1到8范围内的整数; 然后让你从中选出一个最长的子列; ...
- Codeforces Round #384 (Div. 2) //复习状压... 罚时爆炸 BOOM _DONE
不想欠题了..... 多打打CF才知道自己智商不足啊... A. Vladik and flights 给你一个01串 相同之间随便飞 没有费用 不同的飞需要费用为 abs i-j 真是题意杀啊, ...
- 「算法笔记」状压 DP
一.关于状压 dp 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...
随机推荐
- mysqldump: Got errno 28 on write(mysql)
使用mysqldump进行数据库备份的时候,出现下面的错误 mysqldump: Got errno 28 on write 上网查了一下:出现这个错误,是因为磁盘的空间不足 再看系统空间使用 ...
- LUIS 语义识别API调用方法
本例使用itchat获取微信文字消息,发送给LUIS返回识别消息,再将返回消息格式化后通过微信发回 关于itchat的使用参考我的另外一篇随笔itchat个人练习 语音与文本图灵测试例程 # -*- ...
- 在spring boot上基于maven使用redis——批量匹配并删除 (二)
一.背景 在搭建了项目之后,由于需要通过触发动作,并删除redis中多个key. 二.思路 在查询了jedis并没有类似的删除方法之后,事情就变得清晰起来.完成上述任务,分为两个步骤,第一,找到要删除 ...
- selenium +java 多个类公用driver问题
问题点:太久没有写selenium代码,居然把driver公用的问题忘记了,即:每写一个测试类,执行过程中都会新建一个窗口,这样应该说是非常不专业的. 大概想了一个方法,虽然看起来也不怎么专业,但感觉 ...
- Python+MySQL开发医院网上预约系统(课程设计)一
一:开发环境的配置 1:桌面环境为cnetos7+python2.7 2:MySQL的安装与配置 1)MySQL的安装 MySQL官方文档: http://dev.mysql.com/doc/mysq ...
- TW实习日记:前三天
今天是2018年7月20号,周五.从周一开始实习到现在,终于想起来要写日记这种东西了,可以记录一下自己这一天所学所做所知也是蛮不错的.先简单总结一下自己的大学生活吧,算是多姿多彩,体验了很多东西.在大 ...
- Python3实现机器学习经典算法(二)KNN实现简单OCR
一.前言 1.ocr概述 OCR (Optical Character Recognition,光学字符识别)是指电子设备(例如扫描仪或数码相机)检查纸上打印的字符,通过检测暗.亮的模式确定其形状,然 ...
- hadoop的safemode 安全模式
hadoop启动检查副本块数,就会进入safemode safemode的相关情况 虽然不能进行修改文件的操作,但是可以浏览目录结构.查看文件内容的. 在命令行下是可以控制安全模式的进入.退出和查看的 ...
- 常用的os操作方法
os.sep可以取代操作系统特定的路径分隔符.windows下为 “”os.name字符串指示你正在使用的平台.比如对于Windows,它是'nt',而对于Linux/Unix用户,它是'posix' ...
- CF刷刷水题找自信1
CF 1108A Two distinct points 题目意思:给你两个线段的起点和终点,让你给出两个不同的点,这两点分别处于两个不同的线段之中.解题思路:题目说如果存在多种可能的点,随意一组答案 ...