$ 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. 在php中获取 数据库的内容,返回到页面

    <?php header("content-type:text/html;charset=utf-8"); $link=mysqli_connect("localh ...

  2. r hive

    w r只能处理有限量的数据 pdf 467

  3. Java 关键字列表

    字 描述 abstract 抽象方法,抽象类的修饰符 assert 断言条件是否满足 boolean 布尔数据类型 break 跳出循环或者label代码段 byte 8-bit 有符号数据类型 ca ...

  4. tensorflow学习笔记二:入门基础 好教程 可用

    http://www.cnblogs.com/denny402/p/5852083.html tensorflow学习笔记二:入门基础   TensorFlow用张量这种数据结构来表示所有的数据.用一 ...

  5. R语言实现金融数据的时间序列分析及建模

    R语言实现金融数据的时间序列分析及建模 一 移动平均    移动平均能消除数据中的季节变动和不规则变动.若序列中存在周期变动,则通常以周期为移动平均项数.移动平均法可以通过数据显示出数据长期趋势的变动 ...

  6. 流程控制: if分支 while循环 for循环

    流程控制 Python程序执行,一定按照某种规律在执行 1.宏观一定是自上而下(逻辑上方代码一定比逻辑下方代码先执行):顺序结构 2.遇到需要条件判断选择不同执行路线的执行方式:分支结构 3.有些事情 ...

  7. Krustal重构树

    zz:https://blog.csdn.net/ouqingliang/article/details/81206050 Kruskal重构树基于Kruskal算法.在执行算法过程中,Kruskal ...

  8. [Python3 填坑] 011 元组中有多个最值,索引出来的是哪一个

    目录 1. print( 坑的信息 ) 2. 开始填坑 (1) max() (2) min() (3) 结论 1. print( 坑的信息 ) 挖坑时间:2019/01/11 明细 坑的编码 内容 P ...

  9. Hadoop Map/Reduce

    Hadoop Map/Reduce是一个使用简易的软件框架,基于它写出来的应用程序能够运行在由上千个商用机器组成的大型集群上,并以一种可靠容错的方式并行处理上T级别的数据集.一个Map/Reduce ...

  10. linux安装mysql(tar.gz)

    1. 查看卸载自带的mysql # rpm -qa|grep MySQLMySQL-X.X.X#rpm -e MySQL-X.X.X # rpm -qa|grep mariadb #有些版本还得查看卸 ...