首页 > 其他分享 >【题解】CF1110D Jongmah(DP)

【题解】CF1110D Jongmah(DP)

时间:2023-09-30 14:11:40浏览次数:31  
标签:cnt le 题解 选择 连击 DP 顺子 CF1110D dp

【题解】CF1110D Jongmah

代码很短,但是思路我怎么也想不到的神仙 DP。

题意概述

你在玩一个叫做 Jongmah 的游戏,你手上有 \(n\) 个麻将,每个麻将上有一个在 \(1\) 到 \(m\) 范围内的整数 \(a_i\)。

为了赢得游戏,你需要将这些麻将排列成一些三元组,每个三元组中的元素是相同的或者连续的。如 \(7,7,7\) 和 \(12,13,14\) 都是合法的。你只能使用手中的麻将,并且每个麻将只能使用一次。

请求出你最多可以形成多少个三元组。

数据范围

  • \(1 \le n,m \le 10^6\)
  • \(1 \le a_i \le m\)

思路分析

首先我们定义第 \(i\) 个顺子表示三个麻将上写着 \(\{i,i+1,i+2\}\) 的三元组,\(i\) 的三连击表示三个麻将上都写着 \(i\) 的三元组,\(cnt_i\) 表示写着 \(i\) 的麻将数。

那么有一个结论是:对于每个 \(i(1 \le i \le m)\),第 \(i\) 个顺子最多只需要两次。因为 \(3\) 个第 \(i\) 个顺子可以转化为 \(3\) 个三连击(\(i,i+1,i+2\) 的三连击),所以一定存在最优解满足第 \(i\) 个顺子取不超过两次。这是麻将题的常见技巧。

那么我们就可以考虑枚举第 \(i\) 个顺子选了多少次(\(0,1\) 或 \(2\) 次)。

如果直接枚举每个顺子选了多少次,是 \(3^m\) 的复杂度,不能接受。考虑通过 DP 优化。

但是如果直接 DP,发现很难进行状态设计,那么我们可以考虑简化问题。

考虑先解决如下问题:

如果我们并不是可以选择每个顺子,而是只能选择第 \(i\) 个顺子(其中 \(i\bmod 3=1\)),那么如何确定有多少种合法的选择方案。

这个问题的简化之处就在于,第 \(i\) 个的顺子的选择不受任何其它顺子的限制。

那么我们可以直接定义 \(dp_i\) 表示选到了第 \(i\) 个顺子总共有多少种三元组的选择情况。然后枚举选择次数 \(k\),则对于每个 \(i\),选择 \(i\) 的三连击的个数是 \(\left \lfloor\dfrac{cnt_i-k}{3}\right\rfloor\),那么 \(dp_i\) 就可以用 \(dp_{i-3}\) 加上第 \(i\) 个顺子的选择情况再加上 \(i,i-1,i-2\) 的三连击的选择情况而得到,那么有:

\[dp_{i}=\max\limits_{0 \le k \le 2}\{dp_{i-3}+k+\left \lfloor\dfrac{cnt_i-k}{3}\right\rfloor+\left \lfloor\dfrac{cnt_{i-1}-k}{3}\right\rfloor+\left \lfloor\dfrac{cnt_{i-2}-k}{3}\right\rfloor\} \]

这是只能选择第 \(i(i\bmod 3=1)\) 个顺子的情况。


那么对于所有 \(1\le i \le m\) 的每一个 \(i\) 都能选的情况呢?

可以发现这个时候第 \(i\) 个的顺子的选择情况和 \(i\) 的三连击的选择情况,都受到第 \(i-1\) 个顺子的选择情况和第 \(i-2\) 的顺子选择情况的影响,这个时候我们就不能直接定义 \(dp_i\) 表示选到了第 \(i\) 个顺子的方案来解决问题了。我们考虑将第 \(i-1\) 个顺子的选择情况和第 \(i-2\) 个顺子的选择情况加进状态,由于这里第 \(i\) 个顺子的选择情况也会影响到后面第 \(i+1\) 个顺子的选择情况,所以也要把它加进状态,即 \(dp_{i,j,k,t}\) 表示考虑到了第 \(i\) 个顺子,第 \(i\) 个顺子选择了 \(j\) 次,第 \(i-1\) 个顺子选择了 \(k\) 次,第 \(i-2\) 个顺子选了 \(t\) 次的方案数,那么这时候 \(dp_{i,j,k,t}\) 就可以直接由 \(dp_{i-1,k,t,l}\) 其中 \(l\) 是第 \(i-3\) 个顺子的选择情况。

这时候我们发现,第 \(i-3\) 个顺子的选择情况,对第 \(i\) 个顺子的选择情况和 \(i\) 的三连击的选择情况没有影响。同时在 \(dp_{i-1,k,t,l}\) 的状态里已经包含了第 \(i-2\) 个顺子的选择情况,所以我们可以将状态的最后一维删去。那么我们最终确定的 dp 状态就是:\(dp_{i,j,k}\) 表示考虑到了第 \(i\) 个顺子,第 \(i\) 个顺子选择了 \(j\) 次,第 \(i-1\) 个顺子选择了 \(k\) 次的方案数是多少。

那么对于 \(dp_{i,j,k}\),就可以由 \(dp_{i-1,k,t}\) 转移而来,其中 \(t\) 表示第 \(i-2\) 个顺子选择了 \(t\) 次。然后我们枚举 \(j,k,t\),那么 \(dp_{i,j,k}\) 就等于 \(dp_{i-1,k,t}\) 加上第 \(i\) 个顺子选择次数 \(j\) 再加上 \(i\) 的三连击的选择次数。


现在问题就转化为,如何在已知 \(j,k,t\) 的情况下,求 \(i\) 的三连击可以选择多少次。

假设 \(j=1,k=1,t=1\),如图所示:

由该图可知,红色的部分即为三连击的个数,即 \(\left\lfloor\dfrac{cnt_i-j-k-t}{3}\right\rfloor\)。

那么总的转移方程式就为:

\[dp_{i,j,k}=\max\{dp_{i-1,k,t}+j+\left\lfloor\dfrac{cnt_i-j-k-t}{3}\right\rfloor\} \]

时间复杂度 \(O(27n)\)。

代码实现

代码
//CF1110D
//The Way to The Terminal Station…
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
const int maxn=1e6+10;
int dp[maxn][3][3],a[maxn],cnt[maxn];

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

int main()
{
	int n,m;
	n=read();m=read();
	for(int i=1;i<=n;i++)
	{
		a[i]=read();
		cnt[a[i]]++;
	}
	for(int i=1;i<=m;i++)
	{
		for(int j=0;j<3;j++)
		{
			for(int k=0;k<3;k++)
			{
				for(int t=0;t<3;t++)
				{
					if(cnt[i]<j+k+t)continue;
					dp[i][j][k]=max(dp[i][j][k],dp[i-1][k][t]+(cnt[i]-j-k-t)/3+j);
				}
			}
		}
	}
	cout<<dp[m][0][0]<<"\n";
	return 0;
}

标签:cnt,le,题解,选择,连击,DP,顺子,CF1110D,dp
From: https://www.cnblogs.com/xrkforces/p/CF1110D.html

相关文章

  • 洛谷题解 | AT_abc321_c Primes on Interval
    目录题目翻译题目描述输入格式输出格式样例#1样例输入#1样例输出#1样例#2样例输入#2样例输出#2样例#3样例输入#3样例输出#3题目简化题目思路AC代码题目翻译【题目描述】你决定用素数定理来做一个调查.众所周知,素数又被称为质数,其含义就是除了数字一和本身之外不能......
  • 算法题解--蓝桥云课跳跃
    题目蓝桥云课跳跃1.看完题目先写了个二维数组,然后就真的不懂了,最后找了个大概能懂的题解,思路大概是是建立坐标,再用递归求出所有路径,找出其中最大的权值和2.遇到的问题还是没思路,而且写下面使用递归的方法时光出错,不是很熟练3.测试结果:4.收获:学习过的static终于派上了用场,......
  • CF38F 题解
    blog。严重怀疑这题放到2023年至少*2000,评绿合情合理。首先是博弈论。然后数据范围很小。直接暴力DP啪的一下上去了,很快啊!这就抽象起来了。另一篇题解说不能暴力转移,但是你先预处理出来\(num(s)\),然后直接记忆化搜索,暴力枚举每一次操作的字符,这不就做完了吗。具体一点的......
  • [春季测试 2023] 密码锁 题解
    题目传送门闲话duliu题,写了10k。题意形式化地,对于\(1\leqi\leqk\),定义密码锁第\(i\)行的松散度为\[c(i)=\max\limits_{j=1}^na_{i,j}-\min\limits_{j=1}^na_{i,j}\]同时定义整个密码锁的松散度为\[C=\max\limits_{1\leqi\leq......
  • CF961E Tufurama 题解
    CF961ETufurama题解二维数点做法题意  给定长度为\(n\)的序列\(a\),统计二元组\((i,j)\)的个数,使得该二元组满足\(1\leqi<j\leqn,a_i\geqj,a_j\geqi\)。\(n\)在\(2\times10^{5}\)级别,\(a_i\)在\(1\times10^{9}\)级别。思路分析  我们考虑把......
  • [题解] CF1003E - Tree Constructing
    CF1003E-TreeConstructing题目传送门知识点:贪心题意给定\(n\)个顶点,问是否能够构造出一棵直径为\(d\)的树,且每个顶点的度数最多为\(k\)。思路我们要构造出一棵树,使得其直径长度一定为\(d\),那么我们可以先选择\(d+1\)个点,让这些点构成一条树链即可。接着,考虑......
  • P5047 [Ynoi2019 模拟赛] Yuno loves sqrt technology II 题解
    Description给你一个长为\(n\)的排列,\(m\)次询问,每次查询一个区间的逆序对数,强制在线。link\(1\leqn,m\leq10^5\)。Solution考虑分块。首先如果\(l,r\)在同一个块内,可以对于每个块暴力二维前缀和预处理。如果\(l,r\)在不同的块内。设\(bel[l]=x,bel[r]=y\)。首......
  • Go每日一库之178:chromedp(一个基于Chrome DevTools协议的库,支持数据采集、截取网页长
    该库提供了一种简单、高效、可靠的方式来控制Chrome浏览器进行自动化测试和爬取数据。项目地址:https://github.com/chromedp/chromedp它可以模拟用户在浏览器中执行各种操作,如点击、输入文本、截取网页长图、将网页内容转换成pdf文档、下载图片等,从而获取到需要采集的数据。基......
  • CSP-S 2021 廊桥分配 题解
    part1:题目描述:当一架飞机抵达机场时,可以停靠在航站楼旁的廊桥,也可以停靠在位于机场边缘的远机位。乘客一般更期待停靠在廊桥,因为这样省去了坐摆渡车前往航站楼的周折。然而,因为廊桥的数量有限,所以这样的愿望不总是能实现。机场分为国内区和国际区,国内航班飞机只能停靠在国内......
  • [CF762D] Maximum path 题解
    [CF762D]Maximumpath题解想法首先考虑问题的弱化版,如果不能往左走,能取到的最大值是多少。这个问题可以用一个显然的DP解决,\(f_{i,j}\)表示走到第\(i\)列,第\(j\)行,并且不会再访问这一列其它的方格,能取到的最大值。转移可以从三个方向考虑,以\(f_{i,1}\)为例,黑色是当......