[LOJ3084][GXOI/GZOI2019]宝牌一大堆——DP
题目链接:
求最大值容易想到$DP$,但如果将$7$种和牌都考虑进来的话,$DP$状态不好设,我们将比较特殊的七小对和国士无双单独求,其他的进行$DP$。
观察其他五种和牌可以发现,他们都是由$4$组杠子或面子和$1$组雀头组成。
那么可以列出$DP$式子:$f[i][j][k][l][m][n]$表示前$i$种牌,其中有$j$个杠子或面子、$k$个雀头,第$i-2\sim i$种牌分别有$l,m,n$张时前$i-3$种牌的最大值。
转移时对顺子、杠子、刻子和雀头四种情况分别转移即可。
对于国士无双,暴力枚举第$14$张牌是什么然后取最大值即可。
对于七小对,设$F[i][j]$表示前$i$种牌中取了$j$种雀头的最大值,$01$背包转移即可。
#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<vector>
#include<bitset>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define ll long long
using namespace std;
const int mod=1e9+7;
ll f[35][5][2][5][5][5];
ll F[35][8];
char ch[3];
int T;
ll p[6];
ll c[10][10];
int s[35];
int t[35];
bool vis[35]={0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0};
int g[20]={1,9,10,18,19,27,28,29,30,31,32,33,34};
void add(ll &x,ll y)
{
x=max(x,y);
}
int find(char ch[3])
{
if(ch[0]=='E')return 28;
if(ch[0]=='S')return 29;
if(ch[0]=='W')return 30;
if(ch[0]=='N')return 31;
if(ch[0]=='Z')return 32;
if(ch[0]=='B')return 33;
if(ch[0]=='F')return 34;
if(ch[1]=='m')return ch[0]-'0';
if(ch[1]=='p')return 9+ch[0]-'0';
if(ch[1]=='s')return 18+ch[0]-'0';
}
ll get(int id,int num)
{
return t[id]?p[num]:1ll;
}
ll DP()
{
ll res=0;
memset(f,0,sizeof(f));
f[1][0][0][0][0][0]=1ll;
for(int i=1;i<=34;++i)
{
for(int j=0;j<=4;++j)
{
for(int k=0;k<=1;++k)
{
for(int l=0;l<=4;++l)
{
for(int m=0;m<=4;++m)
{
for(int n=0;n<=4;++n)
{
ll now=f[i][j][k][l][m][n];
if(!now)continue;
if(i<34)add(f[i+1][j][k][m][n][0],now*(i>2?c[s[i-2]][l]:1)*get(i-2,l));
if(j<4&&s[i]-n>=3)add(f[i][j+1][k][l][m][n+3],now);
if(j<4&&s[i]-n>=4)add(f[i][j+1][k][l][m][n+4],now);
if(j<4&&vis[i]&&s[i]-n&&s[i-1]-m&&s[i-2]-l)add(f[i][j+1][k][l+1][m+1][n+1],now);
if(k<1&&s[i]-n>=2)add(f[i][j][k+1][l][m][n+2],now);
if(i==34&&j==4&&k==1)add(res,now*c[s[i]][n]*c[s[i-1]][m]*c[s[i-2]][l]*get(i,n)*get(i-1,m)*get(i-2,l));
}
}
}
}
}
}
return res;
}
ll qxd()
{
memset(F,0,sizeof(F));
F[0][0]=1ll;
for(int i=1;i<=34;i++)
{
for(int j=0;j<=7;j++)
{
if(!F[i-1][j])continue;
add(F[i][j],F[i-1][j]);
if(j<7)add(F[i][j+1],F[i-1][j]*c[s[i]][2]*get(i,2));
}
}
return F[34][7]*7;
}
ll gsws()
{
ll res=0;
for(int i=0;i<13;i++)
{
if(!s[g[i]])return 0;
if(s[g[i]]==1)continue;
ll sum=c[s[g[i]]][2]*get(g[i],2);
for(int j=0;j<13;j++)
{
if(i==j)continue;
sum=sum*s[g[j]]*get(g[j],1);
}
add(res,sum*13);
}
return res;
}
int main()
{
for(int i=0;i<=8;i++)
{
c[i][0]=1ll;
for(int j=1;j<=i;j++)
{
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
}
p[0]=1ll;
for(int i=1;i<=4;i++)
{
p[i]=p[i-1]*2ll;
}
scanf("%d",&T);
while(T--)
{
for(int i=1;i<=34;i++)
{
s[i]=4;
}
while(1)
{
scanf("%s",ch);
if(ch[0]=='0')break;
s[find(ch)]--;
}
memset(t,0,sizeof(t));
while(1)
{
scanf("%s",ch);
if(ch[0]=='0')break;
t[find(ch)]=1;
}
ll ans=0;
add(ans,DP());
add(ans,gsws());
add(ans,qxd());
printf("%lld\n",ans);
}
}
[LOJ3084][GXOI/GZOI2019]宝牌一大堆——DP的更多相关文章
- [GXOI/GZOI2019]宝牌一大堆(dp)
luogu bzoj 这个麻将题还算挺友善的,比隔壁zjoi的要好得多... 比较正常的做法是五维dp 但事实上六维dp也是完全不会被卡的 七对子选权值最高的七个,国士无双直接$13^2$暴力 ...
- P5301 [GXOI/GZOI2019]宝牌一大堆
题目地址:P5301 [GXOI/GZOI2019]宝牌一大堆 这里是官方题解(by lydrainbowcat) 部分分 直接搜索可以得到暴力分,因为所有和牌方案一共只有一千万左右,稍微优化一下数据 ...
- 【BZOJ5503】[GXOI/GZOI2019]宝牌一大堆(动态规划)
[BZOJ5503][GXOI/GZOI2019]宝牌一大堆(动态规划) 题面 BZOJ 洛谷 题解 首先特殊牌型直接特判. 然后剩下的部分可以直接\(dp\),直接把所有可以存的全部带进去大力\(d ...
- luogu P5301 [GXOI/GZOI2019]宝牌一大堆
传送门 wdnm又是打麻将 首先国土无双可以直接枚举哪种牌用了\(2\)次算贡献,然后\(7\)个对子可以把每种牌的对子贡献排序,取最大的\(7\)个,剩下的牌直接暴力枚举是不行的,考虑dp,设\(f ...
- 题解 P5301 【[GXOI/GZOI2019]宝牌一大堆】
这道题除了非常恶心以外也没有什么非常让人恶心的地方 当然一定要说有的话还是有的,就是这题和咱 ZJOI 的 mahjong 真的是好像的说~ 于是就想说这道题出题人应该被 锕 掉 noteskey 整 ...
- [GXOI/GZOI2019]宝牌一大堆
感觉比ZJOI的麻将要休闲很多啊. 这个题就是一个最优化问题,没有面子的特殊牌型可以直接用复杂度较低的贪心判掉. 有面子的话就是一个经典dp.(曾经还在ZJOI写过这个毒瘤东西 大概就是存一下对子,面 ...
- [luogu 5301][bzoj 5503] [GXOI/GZOI2019] 宝牌一大堆
题面 好像ZJOI也考了一道麻将, 这是要发扬中华民族的赌博传统吗??? 暴搜都不会打, 看到题目就自闭了, 考完出来之后看题解, \(dp\), 可惜自己想不出来... 对于国士无双(脑子中闪过了韩 ...
- 【题解】Luogu P5301 [GXOI/GZOI2019]宝牌一大堆
原题传送门 首先先要学会麻将,然后会发现就是一个暴力dp,分三种情况考虑: 1.非七对子国士无双,设\(dp_{i,j,k,a,b}\)表示看到了第\(i\)种牌,一共有\(j\)个\(i-1\)开头 ...
- [GX/GZOI2019]宝牌一大堆(DP)
出这种麻将题有意思吗? 乍看很难实则很水,就是麻将式DP,想必大家很熟悉了吧.首先把“国士无双”和“七对子”两种牌型判掉,然后观察牌胡的形式,发现每多一张牌实际上就是把1个面子变成1个杠子,然后可以直 ...
随机推荐
- 【转载】假设有以下代码 String s = “hello”; 阿里巴巴笔试题
原文链接点这里 equals 源码如下: 分析: //true equal用于比较两个对象的值是否相同,和内存地址无关
- 第一节: dingo/API 最新版 V2.0 之安装讲解(连载)
我发现关于dingo/API V2.0的资料少之又少,应该也是发布时间不久的原因.下面,我就来给大家讲解(翻译)下官方的英文文档,如果有说的不对的地方,请指正.先附上,官网wiki地址https:// ...
- Do you have an English name? 你有英文名吗?
文中提到的所有人名都是虚构的,如有雷同,纯属巧合. 当然,你的洋名儿也可能是德文.法文.意大利文,等々々々. 全球化时代,和老外的交流也多了."高端"的程序员想要进欧美系外企,想要 ...
- 用VS2017进行移动开发(C#、VB.NET)——Progress控件,Smobiler移动开发
Progress控件 一. 样式一 我们要实现上图中的效果,需要如下的操作: 从工具栏上的“Smobiler Components”拖动一个Progress控件到窗体界面上 修改Pr ...
- Java高阶语法---static
背景:听说static Java高阶语法是挺进BAT必经之路. static: 静态static,很多时候会令我望文生义,但是get到了static最重要的一点,其他的理解都还ok. static最重 ...
- C++系列总结——继承
前言 前面讲了封装,但封装只是隐藏了类内部实现.如果使用多态隐藏类本身的话,只有封装是不够的,还需要继承. 继承 通过封装.我们把一些相关的函数和变量包裹在了一起,这些函数和变量就叫做类的成员函数和成 ...
- Uncaught ReferenceError: jQuery is not defined
页面调试时,明明引入了JQ文件,却一直提示Uncaught ReferenceError: jQuery is not defined错误. 转自:http://blog.csdn.net/baicp ...
- 开始食用grpc(之二)
开始食用grpc(之二) 转载请注明出处:https://www.cnblogs.com/funnyzpc/p/9570992.html ``` 前段时间有童鞋找我开专栏.搬家.甚至还有人找我写书的. ...
- 关于Java 中跳出多重循环
前言 环境:window10 JDK 1.8 应用场景:在多个for循环或while循环中,直接跳到最外层的循环外面,而不是需要层层退出来. 使用: 使用一个标签label(也可以是其他单词,不能是关 ...
- saiku环境搭建
说明:搭建saiku环境,BI展示工具. 环境说明: os:windows7 jdk:jdk1.6.0_43 tomcat:apache-tomcat-7.0.62 saiku:saiku-ui-2. ...