CH5E26 扑克牌 (计数类DP)
$ CH5E26\times ~ $ 扑克牌: (计数类DP)

$ solution: $
唉,计数类DP总是这么有套路,就是想不到。
这道题我们首先可以发现牌的花色没有价值,只需要知道每种牌有 $ (0,4] $ 张,牌的面值也不用管,只需要知道总共有 $ (0,13] $ 种牌。然后我们就可以设出状态: $ f[i][j][p][q] $ 表示还剩 $ 1 $ 张有 $ i $ 种牌的,还剩 $ 2 $ 张牌的有 $ j $ 种,还剩 $ 3 $ 张牌的有 $ p $ 种,还剩 $ 4 $ 张牌的有 $ q $ 种,
可能有人会问,怎么想到这种方法的。事实上,这是计数类DP的重点。做题目的时候,我们往往需要去题目里挖掘性质,将题目所给条件进行转化或建模 。然后在数据范围上大胆猜想,更具经验判断。计数类DP,博主目前只会两个套路:
- 一个是找基准点(一般用记忆化搜索代替DP)
- 然后就是这一种,直接构造法,我们尤其是构造特殊排列的时候。类比这一题,我们可以用轮廓线DP来模拟构造题目所需排列,轮廓线DP里保存的就是构造到某一阶段所剩余(或用了)的元素。就像25语言那道题目。
所以这一道题我们可以枚举放牌的过程,每一次将牌放到排列末尾。当然对于不同的构造方法,轮廓线DP的实现各有千秋。这一道题之所以难,还在于我们如何让转移达到题目要求。题目里唯一一个棘手的限制就是,相邻的牌面值不同。这个情况如果我们只设四维显然不能明确表示出构造到某一阶段的具体状态。所以我们再加一维用来表示当前排列最后一张牌是从还剩四张(或三张,两张,一张)的牌中取出来的。
这个很重要,举个栗子,我现在拥有某种牌4张,我将其中一张放到排列末尾,那么我下一次放牌时如果从牌数为3三的牌中取牌就有可能抽到与我刚刚放的牌一样的牌,这个需要判断一下。(详细可以见代码,代码里转移中类似 (a-(r==2)) 这样的语句就是用来处理这种情况的)
想必大家读到这里应该已经知道如何转移了吧,我们的下一张牌(就是转移),会有四种情况:(要注意我们多加的那一维的影响)
- 放到排列末尾的那种牌已经只剩一张了,
- 还剩两张
- 还剩三张
- 还剩四张
然后,计数类DP,往往可以用记忆化搜索来带替DP,比较方便。
$ code: $
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<algorithm>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<set>
#define ull unsigned long long
#define ll long long
#define db double
#define rg register int
using namespace std;
int n;
int ch[75],g[5];
ull f[15][15][15][15][5];
inline int qr(){
register char ch; register bool sign=0; rg res=0;
while(!isdigit(ch=getchar()))if(ch=='-')sign=1;
while(isdigit(ch))res=res*10+(ch^48),ch=getchar();
if(sign)return -res; else return res;
}
inline ull ask(int a,int b,int c,int d,int r){
ull res=f[a][b][c][d][r]; if(res)return res;
if(a)res=res+ask(a-1,b,c,d,1)*(a-(r==2));
if(b)res=res+ask(a+1,b-1,c,d,2)*2*(b-(r==3));
if(c)res=res+ask(a,b+1,c-1,d,3)*3*(c-(r==4));
if(d)res=res+ask(a,b,c+1,d-1,4)*4*d;
return f[a][b][c][d][r]=res;
}
int main(){
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
for(rg i=0;i<=4;++i)f[0][0][0][0][i]=1;
rg t,ff=0; t=qr();
while(t--){
n=qr(); string s;
for(rg i=1;i<=n;++i) cin>>s,++ch[s[0]-49];
for(rg i=1;i<=4;++i) g[i]=0;
for(rg i=0;i<=50;++i) ++g[ch[i]],ch[i]=0;
printf("Case #%d: ",++ff);
cout<<ask(g[1],g[2],g[3],g[4],0)<<endl;;
}
return 0;
}
CH5E26 扑克牌 (计数类DP)的更多相关文章
- 动态规划——区间DP,计数类DP,数位统计DP
本博客部分内容参考:<算法竞赛进阶指南> 一.区间DP 划重点: 以前所学过的线性DP一般从初始状态开始,沿着阶段的扩张向某个方向递推,直至计算出目标状态. 区间DP也属于线性DP的一种, ...
- SDOI2010代码拍卖会 (计数类DP)
P2481 SDOI2010代码拍卖会 $ solution: $ 这道题调了好久好久,久到都要放弃了.洛谷的第五个点是真的强,简简单单一个1,调了快4个小时! 这道题第一眼怎么都是数位DP,奈何数据 ...
- $Poj1737\ Connected\ Graph$ 计数类$DP$
AcWing Description 求$N$个节点的无向连通图有多少个,节点有标号,编号为$1~N$. $1<=N<=50$ Sol 在计数类$DP$中,通常要把一个问题划分成若干个子问 ...
- $CF559C\ Gerald\ and\ Fiant\ Chess$ 计数类$DP$
AcWing Description 有个$H$行$W$列的棋盘,里面有$N$个黑色格子,求一个棋子由左上方格子走到右下方格子且不经过黑色格子的方案数. $1<=H,M<=1e5,1< ...
- $CH5302$ 金字塔 区间$DP$/计数类$DP$
CH Sol f[l][r]表示l到r这段区间对应的金字塔结构种数 发现是f[l][r]是可以由比它小的区间推出来的 比如已知f[l+1][k],f[k+1][r],不难想到f[l][r]+=f[l+ ...
- hackerrank【Lego Blocks】:计数类dp
题目大意: 修一个层数为n,长度为m的墙,每一层可以由长度为1.2.3.4的砖块构成. 每一层都在同一个长度处出现缝隙是方案非法的,问合法的方案数有多少种 思路: 先求出总方案,再减去所有非法的方案数 ...
- codeforces 277.5 div2 F:组合计数类dp
题目大意: 求一个 n*n的 (0,1)矩阵,每行每列都只有两个1 的方案数 且该矩阵的前m行已知 分析: 这个题跟牡丹江区域赛的D题有些类似,都是有关矩阵的行列的覆盖问题 牡丹江D是求概率,这个题是 ...
- Codeforces 9D How many trees? 【计数类DP】
Codeforces 9D How many trees? LINK 题目大意就是给你一个n和一个h 问你有多少个n个节点高度不小于h的二叉树 n和h的范围都很小 感觉有无限可能 考虑一下一个很显然的 ...
- Codeforces 28C Bath Queue 【计数类DP】*
Codeforces 28C Bath Queue LINK 简要题意:有 n 个人等概率随机进入 m 个房间,一个房间可以有多个人,第 i 个房间有 ai 个水龙头,在一个房间的人要去排队装水,他们 ...
随机推荐
- 基于python实现自动化办公学习笔记四
PPT(1)写PPT import win32comimport win32com.client def makeppt(path): ppt = win32com.client.Dispatch(& ...
- CruiseControl.NET配置
CruiseControl.NET简介 CruiseControl.NET是.net平台下,一个开源的自动化持续集成工具. 它是一个程序套件,但其核心是一个叫做CruiseControl.NET Se ...
- InfluxDB安装使用
influxdb简介 启动步骤 服务启停:sudo service influxdb start/stop/restart 安装过程: 1.增加yum源 cat <<EOF | sud ...
- php中钩子(hook)的应用示例demo
我们先来回顾下原本的开发流程:产品汪搞出了一堆需求:当用户注册成功后需要发送短信.发送邮件等等:然后聪明机智勇敢的程序猿们就一扑而上:把这些需求转换成代码扔在 用户注册成功 和 跳转到首页 之间: 没 ...
- DRF中的视图集的使用
1.说明:DRF框架中的视图集: 在drf开发接口中,使用GenericAPIView和视图扩展类结合起来完成接口功能是一件很常见的事情,所以,drf的作者帮我们提前把 GenericAPIView ...
- 红米note2 刷机 注意问题:
其他的百度都有,用刷线宝刷 红米note2 刷机 注意问题: 关机状态线下,链接电脑,按着音量下键不松手,按电源键开机后松开,即进入刷机模式. 其中,红米,红米1s移动,红米note移动3g/联通 ...
- 001/Node.js(Mooc)--基础知识
一.Node.js基础知识 node.js用C++语言编写. 简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrome JavaScript 运行时 ...
- Angular5 import interface 报错:XXX is not a module
在项目里定义了一个interface,device.ts.然后在component.ts中要使用这个interface,import之后,VSCode报错:‘xxx/xxx/xxx/device.ts ...
- little-endian And big-endian
coming from http://zhidao.baidu.com/link?url=B_7AA_O6TkCVlKw9t_Xifu6TzpaFUiDEVkH1iTRT4vUGD0uRmazwduf ...
- JDK11 | 第五篇 : 启动单个Java源代码文件的程序
文章首发于公众号<程序员果果> 地址 : https://mp.weixin.qq.com/s/h1L4FmzVSix434gVt8Fc7w 一.简介 JEP330-启动单文件代码程序(L ...