[ABC176F] Brave CHAIN
[ABC176F] Brave CHAIN
题意
给你 \(3n\) 个数字。每次你可以选取前 \(5\) 个数字,拿走里面任意三个数字,剩下两个,如果拿走的 \(3\) 个数字相等,得分 \(+1\)。问最大得分是多少。
思路
首先我们想尝试贪心。然而不好贪心,因为你不知道前面会给你留下哪两张牌,留下的方案数很多。
题目可以看做每次有三个新数字,和前面两个留下的数字进行操作,它们中留下两个。
此时可以考虑 DP。由前面思考或者部分分提示可以设出 \(dp_{i,x,y}\) 表示考虑到第 \(i\) 组数字(\(3\) 个为一组),留下 \(x,y\) 的最大分数。
于是我们要枚举前面留下哪两个数字,五个数字中留下哪两个数字,状态是 \(O(nV^2)\),转移考虑一下留下哪两个数字,是常数复杂度,总共 \(O(nV^2)\)。
考虑如何优化。
首先枚举 \(i\) 是必须的,不过空间上可以把这一维滚掉。状态感觉都很有用。
考虑优化转移。分为得分和不得分两种情况考虑,这样代码好写一些吧。设新的三个数字为 \(a,b,c\)。若 \(a=b=c\),我们直接删除这三个数字得分 \(+1\),且这样是一定不劣的。反正它们迟早都要删掉,就不必留到后面了。因此这种情况全局 \(+1\),可以维护一个 tag。虽然存在不得分的更新方式,但是根据贪心,我们最后的最大得分方案中一定没有把这三个新数留下的情况,这是不优的,因此这种情况不用考虑不得分的转移。
若 \(a,b,c\) 有两个相等,设 \(a=b\)。可以在前面找一个 \(x=a=b,y\in[1,n]\),进行转移,剩下的牌就是 \(c,y\),得分 \(+1\)。也可以在前面找 \(x=y=c\),剩下 \(a,b\),得分 \(+1\)。
若 \(a,b,c\) 互不相同,可以在前面找 \(x=y=a \operatorname{or} b\operatorname{or} c\),这里假设选择了 \(a\)。那么剩下的是 \(b,c\),得分 \(+1\)。
以上转移都是 \(O(n)\) 或 \(O(1)\) 的。下面讨论不得分的情况。
为了方便,不得分的情况可以不用考虑 \(a,b,c\) 相等的情况。虽然这样可能会把得分的情况算入不得分,但由于我们的 \(dp\) 值是取 \(\max\),所以没有关系。
若新数留下两个假设是 \(a,b\),那么剩下状态是 \(a,b\),得分不变。得分等于 \(x,y\) 任取的最大值,可以在上一层 \(dp\) 顺便维护,时间复杂度是 \(O(1)\) 的。
若剩下 \(a,x\),则剩下状态为 \(a,x\),我们必须枚举 \(x\),毕竟它是目前一层的状态。然后对所有可能的 \(y\in[1,n]\) 取最大值,这个也可以在上一层 DP 的时候顺便维护。时间复杂度 \(O(n)\)。
若剩下 \(x,y\),则我们要枚举所有 \(x,y\),因为这是状态。但是你发现上面所有的转移都最多只有 \(O(n)\),而且这个转移极为美丽,它是由 \(x,y\to x,y\) 的。一个小技巧是把上面的转移用临时数组存下来,只有 \(O(n)\) 个,做完上面转移后直接把数组盖到原 DP 数组上,这样我们就不用 copy 一遍 \(n^2\) 的 DP 数组了。
总时间复杂度 \(O(n^2)\)。
code
#include<bits/stdc++.h>
//#define LOCAL
#define sf scanf
#define pf printf
#define rep(x,y,z) for(int x=y;x<=z;x++)
#define per(x,y,z) for(int x=y;x>=z;x--)
#define isdigit(x) (x>='0'&&x<='9')
using namespace std;
typedef long long ll;
const int N=3e3+7;
template <typename T>
inline void read(T &x) {
	x=0;
	char ch=getchar();
	while(!isdigit(ch)) ch=getchar();
	for(;isdigit(ch);ch=getchar()) x=(x<<3)+(x<<1)+ch-'0';
}
template <typename T>
inline void write(T x) {
	static int st[10];
	int top=0;
	do {
		st[top++]=x%10;
		x/=10;
	}while(x);
	while(top) putchar(st[--top]+'0');
}
template <typename T>
inline void write(T x,char ch) {
	write(x),putchar(ch);
}
int n;
int a[N*3];
int f[N][N],lamax,g[N],s;
void update(int &mx,int &mx1,int &mx2,int &a,int b,int c) {
	if(b) a=max(a,b+c);
	mx=max(mx,a);mx1=max(mx1,a),mx2=max(mx2,a);
}
struct node{
	int x,y,z,p;
};
vector<node> vec;
int main() {
	#ifdef LOCAL
	freopen("in.txt","r",stdin);
	freopen("my.out","w",stdout);
	#else
	freopen("b.in","r",stdin);
	freopen("b.out","w",stdout);
	#endif
	read(n);
	rep(i,1,n*3) {
		read(a[i]);
	}
	int x=a[1],y=a[2];
	if(x>y) swap(x,y);
	f[x][y]=1;
	lamax=1,g[x]=g[y]=1;
	rep(i,1,n-1) {
		vec.clear();
		int b[3]={a[i*3],a[i*3+1],a[i*3+2]};
		if(b[0]==b[1]&&b[0]==b[2]) { s++;continue;}
		if(b[0]==b[1]||b[0]==b[2]||b[1]==b[2]) {
			int c1=0,c3=0;
			if(b[0]==b[1]) c1=0,c3=2;
			else if(b[0]==b[2]) c1=0,c3=1;
			else c1=1,c3=0;
			rep(k,1,n) {
				int x=k,y=b[c3];
				if(x>y) swap(x,y);
				int xx=k,yy=b[c1];
				if(xx>yy) swap(xx,yy);
				vec.push_back({x,y,f[xx][yy],1});
			}
			vec.push_back({b[c1],b[c1],f[b[c3]][b[c3]],1});
		}else {
			int x=b[1],y=b[2];if(x>y) swap(x,y);
			vec.push_back({x,y,f[b[0]][b[0]],1});
			x=b[0],y=b[2];if(x>y) swap(x,y);
			vec.push_back({x,y,f[b[1]][b[1]],1});
			x=b[0],y=b[1];if(x>y) swap(x,y);
			vec.push_back({x,y,f[b[2]][b[2]],1});
		}
		int x=b[1],y=b[2];if(x>y) swap(x,y);
		vec.push_back({x,y,lamax,0});
		x=b[0],y=b[2];if(x>y) swap(x,y);
		vec.push_back({x,y,lamax,0});
		x=b[0],y=b[1];if(x>y) swap(x,y);
		vec.push_back({x,y,lamax,0});
		rep(k,1,n) {
			rep(c,0,2) {
				int x=b[c],y=k;
				if(x>y) swap(x,y);
				vec.push_back({x,y,g[k],0});
			}
		}
		for(auto tmp : vec) {
			update(lamax,g[tmp.x],g[tmp.y],f[tmp.x][tmp.y],tmp.z,tmp.p);
		}
	}
	int ans=lamax+s;
	if(f[a[n*3]][a[n*3]]) ans=max(ans,f[a[n*3]][a[n*3]]+s+1);
	pf("%d\n",ans-1);
}
												
											[ABC176F] Brave CHAIN的更多相关文章
- AT [ABC176F] Brave CHAIN
		
首先可以发现这样一个事实:在每次操作当中,都有三张牌是已经固定的,只有两张牌是不确定的,于是我们可以发下每一次操作的状态可以简单的使用这两张牌来描述,于是可以考虑令 \(dp_{i, j, k}\) ...
 - zipkin-client:brave核心代码思路整理
		
Zipkin是分布式跟踪系统. 简单地理解,可以将Zipkin分为两部分. 一部分为Zipkin Server,其负责接受存储应用程序处理耗时数据,以及UI展示. 另一部分为Zipkin Client ...
 - HDU 1856 Brave Game(巴什博奕)
		
十年前读大学的时候,中国每年都要从国外引进一些电影大片,其中有一部电影就叫<勇敢者的游戏>(英文名称:Zathura),一直到现在,我依然对于电影中的部分电脑特技印象深刻. 今天,大家选择 ...
 - STM32用JLINK 烧写程序时出现NO Cortex-m device found in JTAG chain现象和解决方案
		
现象 CPU: STM32107VC 用JLINK 烧写程序时出现NO Cortex-m device found in JTAG chain 如图无法查找到硬件就是CPU 提示1:NO Cortex ...
 - 责任链模式/chain of responsibility/行为型模式
		
职责链模式 chain of responsibility 意图 使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有一个对象处 ...
 - 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
		
题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...
 - arm,iptables: No chain/target/match by that name.
		
最近由于项目需要,需要打开防火墙功能. 公司有 arm linux 3.0x86 linux 3.2x86 linux 2.4 的三个嵌入式.都需要打开防火墙功能. 执行“whereis iptabl ...
 - C#设计模式系列:职责链模式(Chain of Responsibility)
		
1.职责链模式简介 1.1>.定义 职责链模式是一种行为模式,为解除请求的发送者和接收者之间的耦合,而使多个对象都有机会处理这个请求.将这些对象连接成一条链,并沿着这条链传递该请求,直到有一个对 ...
 - [工作中的设计模式]责任链模式chain
		
一.模式解析 责任链模式是一种对象的行为模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并不知 ...
 - track message forwards, avoiding request loops, and identifying the protocol capabilities of all senders along the request/response chain
		
https://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html The TRACE method is used to invoke a remote, ...
 
随机推荐
- vs 编译加速
			
简介 充分利用多核的性质 参考链接 https://blog.csdn.net/fanyun_01/article/details/79122455 主要用 2)项目-属性-配置属性-C/C++--- ...
 - Day6 备战CCF-CSP练习
			
Day 6 题目描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行. 你的程序还需支持大小写敏感选项:当选项打开时,表示同一个字母的大写和小写看作不同的字符:当选项关闭时,表示同一个字 ...
 - POLIR-Society-Organization-Politics: “How”-政治分析+组织建设:资源整合:集成"组织"+"人才"+"资源"+"资本" + 商业运营模式(本质问题:目标客户+问题+风险收益)
			
POLIR-Society-Organization-Politics: "How"-政治分析+组织建设: 资源整合,集成: 决策层: 大政方针 VS 执行层: 解决问题 决策层: ...
 - SciTech-Mathematics-Probability+Statistics-Distribution: fitter(Jupyter/Scipy/Python) + distributionFitter(分布拟合器): 交互式概率分布拟合 导入MATLAB® 工作区的数据
			
Distribution Fitter for Jupyter/Scipy/Python Using scipy for data fitting https://education.molssi.o ...
 - SciTech-Mathmatics-Physics-Particle Physics-Election+Photon+Quantum: Parallel Universe + Superposition + Wave-Particle Duality.
			
SciTech-Mathmatics-Quantum LaTex: https://tex.stackexchange.com/questions/483996/automatically-sized ...
 - ICEE-Power-TL431(精准可调Vref基准参考电压源):"稳压精准" 是TL431用"闭环负反馈"钳位"比例采样"处电压为2.5V ("采样电压与"Vref"输入OpAmp放大两者"差值"后驱动 MOSFET导通度) +分流补偿式动态稳压IC) + 实例充电器(TL431+MOS管充满自停)
			
English Words: Cathode: n, 阴极 Anode: n, 阳极 TL431应用实例: 充电器(TL431+MOS管充满自停) MCU 或 OpAmp 用 三极管适配 以驱动 高V ...
 - 【VMware vSphere】借助 Live Patch 无停机修补 vSphere 9 集群。
			
还记得 VMware vSphere 8 U3 中更新的有关 vSphere 生命周期管理功能吗?其中,vSphere Lifecycle Manager 引入了一个叫 "Live Patc ...
 - 2024年1月份更新「GIS数据」全国的GeoJSON、shp格式数据下载获取(精确到乡镇街道级)
			
发现个可以免费下载全国 geojson 数据的网站,推荐一下.支持全国.省级.市级.区/县级.街道/乡镇级以及各级的联动数据,支持导入矢量地图渲染框架中使用,例如:D3.Echarts等 geojso ...
 - CF1946E 题解
			
Blog 赛场上差一点做出来. 首先发现左右两部分是比较独立的,所以可以分开计算后合并. 注意到我们可以把整个数集分成左右两部分,即 \(\binom{n - 1}{p_{m1} - 1}\). 然后 ...
 - .NET 10 中的新增功能系列文章1——运行时中的新增功能
			
引言 随着 .NET 10 预览版6的发布,微软在运行时层面带来了一系列重要的性能改进和新功能.这些改进主要集中在JIT编译器优化.硬件指令集支持.内存管理等方面,旨在进一步提升应用程序的执行效率和资 ...