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



$ solution: $

唉,计数类DP总是这么有套路,就是想不到。

这道题我们首先可以发现牌的花色没有价值,只需要知道每种牌有 $ (0,4] $ 张,牌的面值也不用管,只需要知道总共有 $ (0,13] $ 种牌。然后我们就可以设出状态: $ f[i][j][p][q] $ 表示还剩 $ 1 $ 张有 $ i $ 种牌的,还剩 $ 2 $ 张牌的有 $ j $ 种,还剩 $ 3 $ 张牌的有 $ p $ 种,还剩 $ 4 $ 张牌的有 $ q $ 种,

可能有人会问,怎么想到这种方法的。事实上,这是计数类DP的重点。做题目的时候,我们往往需要去题目里挖掘性质,将题目所给条件进行转化或建模 。然后在数据范围上大胆猜想,更具经验判断。计数类DP,博主目前只会两个套路:

  1. 一个是找基准点(一般用记忆化搜索代替DP)
  2. 然后就是这一种,直接构造法,我们尤其是构造特殊排列的时候。类比这一题,我们可以用轮廓线DP来模拟构造题目所需排列,轮廓线DP里保存的就是构造到某一阶段所剩余(或用了)的元素。就像25语言那道题目。

所以这一道题我们可以枚举放牌的过程,每一次将牌放到排列末尾。当然对于不同的构造方法,轮廓线DP的实现各有千秋。这一道题之所以难,还在于我们如何让转移达到题目要求。题目里唯一一个棘手的限制就是,相邻的牌面值不同。这个情况如果我们只设四维显然不能明确表示出构造到某一阶段的具体状态。所以我们再加一维用来表示当前排列最后一张牌是从还剩四张(或三张,两张,一张)的牌中取出来的。

这个很重要,举个栗子,我现在拥有某种牌4张,我将其中一张放到排列末尾,那么我下一次放牌时如果从牌数为3三的牌中取牌就有可能抽到与我刚刚放的牌一样的牌,这个需要判断一下。(详细可以见代码,代码里转移中类似 (a-(r==2)) 这样的语句就是用来处理这种情况的)

想必大家读到这里应该已经知道如何转移了吧,我们的下一张牌(就是转移),会有四种情况:(要注意我们多加的那一维的影响)

  1. 放到排列末尾的那种牌已经只剩一张了,
  2. 还剩两张
  3. 还剩三张
  4. 还剩四张

然后,计数类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)的更多相关文章

  1. 动态规划——区间DP,计数类DP,数位统计DP

    本博客部分内容参考:<算法竞赛进阶指南> 一.区间DP 划重点: 以前所学过的线性DP一般从初始状态开始,沿着阶段的扩张向某个方向递推,直至计算出目标状态. 区间DP也属于线性DP的一种, ...

  2. SDOI2010代码拍卖会 (计数类DP)

    P2481 SDOI2010代码拍卖会 $ solution: $ 这道题调了好久好久,久到都要放弃了.洛谷的第五个点是真的强,简简单单一个1,调了快4个小时! 这道题第一眼怎么都是数位DP,奈何数据 ...

  3. $Poj1737\ Connected\ Graph$ 计数类$DP$

    AcWing Description 求$N$个节点的无向连通图有多少个,节点有标号,编号为$1~N$. $1<=N<=50$ Sol 在计数类$DP$中,通常要把一个问题划分成若干个子问 ...

  4. $CF559C\ Gerald\ and\ Fiant\ Chess$ 计数类$DP$

    AcWing Description 有个$H$行$W$列的棋盘,里面有$N$个黑色格子,求一个棋子由左上方格子走到右下方格子且不经过黑色格子的方案数. $1<=H,M<=1e5,1< ...

  5. $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+ ...

  6. hackerrank【Lego Blocks】:计数类dp

    题目大意: 修一个层数为n,长度为m的墙,每一层可以由长度为1.2.3.4的砖块构成. 每一层都在同一个长度处出现缝隙是方案非法的,问合法的方案数有多少种 思路: 先求出总方案,再减去所有非法的方案数 ...

  7. codeforces 277.5 div2 F:组合计数类dp

    题目大意: 求一个 n*n的 (0,1)矩阵,每行每列都只有两个1 的方案数 且该矩阵的前m行已知 分析: 这个题跟牡丹江区域赛的D题有些类似,都是有关矩阵的行列的覆盖问题 牡丹江D是求概率,这个题是 ...

  8. Codeforces 9D How many trees? 【计数类DP】

    Codeforces 9D How many trees? LINK 题目大意就是给你一个n和一个h 问你有多少个n个节点高度不小于h的二叉树 n和h的范围都很小 感觉有无限可能 考虑一下一个很显然的 ...

  9. Codeforces 28C Bath Queue 【计数类DP】*

    Codeforces 28C Bath Queue LINK 简要题意:有 n 个人等概率随机进入 m 个房间,一个房间可以有多个人,第 i 个房间有 ai 个水龙头,在一个房间的人要去排队装水,他们 ...

随机推荐

  1. 走进JavaWeb技术世界14:Mybatis入门

    本系列文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查看 https://github.com/h2pl/Java-Tutorial 喜欢的话麻烦点下 ...

  2. 2018-2019-2 20175214 实验三《敏捷开发与XP实践》实验报告

    一.实验内容 1.编码标准:在IDEA中使用工具(Code->Reformate Code)把下面代码重新格式化,再研究一下Code菜单,找出一项让自己感觉最好用的功能.提交截图,加上自己学号水 ...

  3. 获取oracle数据库对象定义

    在oracle中,使用DBMS_METADATA包中的GET_DDL函数来获得对应对象的定义语句.GET_DDL函数的定义如下: DBMS_METADATA.GET_DDL ( object_type ...

  4. WPF UI Close button

    <Window x:Class="WpfApplication1.MainWindow" xmlns="http://schemas.microsoft.com/w ...

  5. 基于Skyline的web开发(6.x)

    多窗口对比 一个页面加载多个TerraExplorer3DWindow和SGWorld等只有第一个能用(即使用iframe也是一样) 所以我决定打开两个新页面实现多窗口对比,然后我在<主页面&g ...

  6. Powershell 音乐播放

    目录 目录 前言 systemwindowsmediamediaplayer 前言 Powershell抱着.NET的大腿,与生俱来了许多非常便捷的功能.例如--音乐的自动播放 system.wind ...

  7. malloc函数分配内存失败的常见原因

    malloc()函数分配内存失败的常见原因:  1. 内存不足.  2. 在前面的程序中出现了内存的越界访问,导致malloc()分配函数所涉及的一些信息被破坏.下次再使用malloc()函数申请内存 ...

  8. 《图解设计模式》读书笔记7-1 facade模式

    目录 1. Facade模式简介 2. 示例程序 2.1 类图 2.2 程序 3.角色和类图 4.思路拓展 1. Facade模式简介 开发程序的过程中,随着时间的推移,类会越来越多,调用关系会越来越 ...

  9. 《计算机程式设计》Week4 课堂笔记

    本笔记记录自 Coursera课程 <计算机程式设计> 台湾大学 刘邦锋老师 Week4 Functions 4-1 System Function 函数主要分为两大类系统定义函数与使用者 ...

  10. struts2 基础3 文件上传、拦截器

    文件上传: 1.将头设置为enctype=”multipart/form-data” <form action="${pageContext.request.contextPath } ...