[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 为了规避不确定性,我们将需要枚举的东西放入状态.当不确定性太多的时候,我们就需要将它们压进较少的维数内. 常见的状态: 天生二进制(开关.选与不选.是否出现--) 爆搜出状态,给它 ...
随机推荐
- 【LG3242】 [HNOI2015]接水果
题面 洛谷 题解 20pts 对于\(n,P,Q\leq 3000\),暴力判断每条路径的包含关系然后排序\(kth\)即可,复杂度\(O(PQ\log P)\) 另30pts 原树为一条链. 发现对 ...
- (转) 理解Angular中的$apply()以及$digest()
原文地址:http://blog.csdn.net/dm_vincent/article/details/38705099 $apply()和$digest()在AngularJS中是两个核心概念,但 ...
- Windows网络通信(一):socket同步编程
网络通信常用API 1. WSAStartup用于初始化WinSock环境 int WSAStartup( WORD wVersionRequested, LPWSADATA lpWSAData ); ...
- shell loop
#!/bin/sh date i=0 while [ $i -le 30 ] do echi $i /usr/sbin/r2/np_test_acl -f rule.txt i=$(e ...
- Git生成SSH密钥
git config --global user.name "yangjianliang"配置用户名 git config --global user.email "52 ...
- Jmeter性能测试使用记录
使用背景 由于最近公司要求对一批接口做性能测试,所以重拾了一些对于Jmeter的使用,现将部分过程做记录,以便以后回溯. 接口参数化 数据参数文件使用了excel保存出的csv文件,dat格式的文件也 ...
- Unity FSM 有限状态机
翻译了一下unity wiki上对于有限状态机的案例,等有空时在详细写一下.在场景中添加两个游戏物体,一个为玩家并修改其Tag为Player,另一个为NPC为其添加NPCControl脚本,并为其将玩 ...
- pager-taglib2.0中文传参乱码问题
1.重现问题 在web项目中有时会用到pager-taglib来作为分页的标签,如上图红色框标识所示,当我们需要把页面参数保持的时候我们会在<pg:param />标签中把参数进行传递. ...
- c# 消息机制篡改
1.背景介绍: c#程序想要针对某个的消息进行别的行为.例如:窗体不可拖动. 2.应用函数WinProc 以窗口不可拖动举例: const int WM_NCLBUTTONDOWN = 0x00A1; ...
- OpenCV学习笔记——imread、imwrite以及imshow
1.imread Loads an image from a file. 从文件中读取图像. C++: Mat imread(const string& filename, int flags ...