【题解】CF1110D Jongmah(DP)
【题解】CF1110D Jongmah
代码很短,但是思路我怎么也想不到的神仙 DP。
题目链接
题意概述
你在玩一个叫做 Jongmah 的游戏,你手上有
为了赢得游戏,你需要将这些麻将排列成一些三元组,每个三元组中的元素是相同的或者连续的。如
请求出你最多可以形成多少个三元组。
数据范围
思路分析
首先我们定义第
那么有一个结论是:对于每个
那么我们就可以考虑枚举第
如果直接枚举每个顺子选了多少次,是
但是如果直接 DP,发现很难进行状态设计,那么我们可以考虑简化问题。
考虑先解决如下问题:
如果我们并不是可以选择每个顺子,而是只能选择第
个顺子(其中 ),那么如何确定有多少种合法的选择方案。
这个问题的简化之处就在于,第
那么我们可以直接定义
这是只能选择第
那么对于所有
可以发现这个时候第
这时候我们发现,第
那么对于
现在问题就转化为,如何在已知
假设
由该图可知,红色的部分即为三连击的个数,即
那么总的转移方程式就为:
时间复杂度
代码实现
代码
//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;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
2022-09-30 【题解】P2167 [SDOI2009]Bill的挑战(状压 DP)