【题解】Luogu P5301 [GXOI/GZOI2019]宝牌一大堆

时间:2022-02-03 09:23:56

原题传送门

首先先要学会麻将,然后会发现就是一个暴力dp,分三种情况考虑:

1.非七对子国士无双,设\(dp_{i,j,k,a,b}\)表示看到了第\(i\)种牌,一共有\(j\)个\(i-1\)开头的顺子,有\(k\)个\(i\)开头的顺子,有\(a\)个面子/杠子,有\(b\)个雀头时最大分数,暴力转移即可

2.七对子,设\(dp_{i,j}\)表示看到了第\(i\)种牌,一共有\(j\)个雀头时最大分数,暴力转移即可

3.国士无双,设\(dp_{i,j}\)表示看到了国士无双限定的第\(i\)张牌,已经选了\(j\)张牌时最大分数,暴力转移即可

最后比个最大就星了

#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int T,v,cnt[35],mrk[35];
ll C[5][5]={
{1,0,0,0,0},{1,1,0,0,0},{1,2,1,0,0},{1,3,3,1,0},{1,4,6,4,1}
};
ll bin[5]={1,2,4,8,16};
inline void upd(register ll &x,register ll y)
{
x=x>y?x:y;
}
inline ll chose(register int x,register int y)
{
return C[cnt[x]][y]*(mrk[x]?bin[y]:1);
}
inline ll work1()
{
static ll dp[35][3][3][5][2];
memset(dp,0,sizeof(dp));
dp[0][0][0][0][0]=1;
for(register int i=0;i<34;++i)
for(register int j=0;j<3;++j)
if(!j||i>7&&(i-7)%9!=0&&(i-7)%9!=1)
for(register int k=0;k<3;++k)
if(!k||i>7&&(i-7)%9!=8&&(i-7)%9!=0)
if(cnt[i+1]>=j+k)
for(register int a=j+k;a<=4;++a)
for(register int b=0;b<=1;++b)
if(dp[i][j][k][a][b])
{
for(register int c=0;c<=2&&j+k+c<=cnt[i+1]&&a+c<=4;++c)
for(register int d=0;j+k+c+d*3<=cnt[i+1]&&a+c+d<=4;++d)
{
int t=j+k+c+d*3;
upd(dp[i+1][k][c][a+c+d][b],dp[i][j][k][a][b]*chose(i+1,t));
if(!b&&t+2<=cnt[i+1])
upd(dp[i+1][k][c][a+c+d][1],dp[i][j][k][a][b]*chose(i+1,t+2));
}
if(cnt[i+1]-j-k==4&&a<4)
upd(dp[i+1][k][0][a+1][b],dp[i][j][k][a][b]*chose(i+1,4));
}
return dp[34][0][0][4][1];
}
inline ll work2()
{
static ll dp[35][8];
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(register int i=0;i<34;++i)
for(register int j=0;j<=7;++j)
{
upd(dp[i+1][j],dp[i][j]);
if(j<7)
upd(dp[i+1][j+1],dp[i][j]*chose(i+1,2));
}
return dp[34][7]*7;
}
int id[]={0,1,2,3,4,5,6,7,8,16,17,25,26,34};
inline ll work3()
{
static ll dp[14][15];
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(register int i=0;i<13;++i)
for(register int j=0;j<=14;++j)
for(register int k=1;k<=cnt[id[i+1]]&&k<=2;++k)
upd(dp[i+1][j+k],dp[i][j]*chose(id[i+1],k));
return dp[13][14]*13;
}
inline int read()
{
int v;
char str[5];
scanf("%s",str);
if(str[0]=='0')
return 0;
if(strlen(str)==1)
{
if(str[0]=='E')
v=1;
else if(str[0]=='S')
v=2;
else if(str[0]=='W')
v=3;
else if(str[0]=='N')
v=4;
else if(str[0]=='Z')
v=5;
else if(str[0]=='B')
v=6;
else
v=7;
}
else
{
if(str[1]=='m')
v=7;
else if(str[1]=='p')
v=16;
else
v=25;
v+=str[0]-'0';
}
return v;
}
int main()
{
scanf("%d",&T);
while(T--)
{
for(register int i=1;i<=34;++i)
cnt[i]=4,mrk[i]=0;
while(v=read())
--cnt[v];
while(v=read())
mrk[v]=1;
write(max(work1(),max(work2(),work3()))),puts("");
}
return 0;
}

【题解】Luogu P5301 [GXOI/GZOI2019]宝牌一大堆的更多相关文章

  1. luogu P5301 &lbrack;GXOI&sol;GZOI2019&rsqb;宝牌一大堆

    传送门 wdnm又是打麻将 首先国土无双可以直接枚举哪种牌用了\(2\)次算贡献,然后\(7\)个对子可以把每种牌的对子贡献排序,取最大的\(7\)个,剩下的牌直接暴力枚举是不行的,考虑dp,设\(f ...

  2. P5301 &lbrack;GXOI&sol;GZOI2019&rsqb;宝牌一大堆

    题目地址:P5301 [GXOI/GZOI2019]宝牌一大堆 这里是官方题解(by lydrainbowcat) 部分分 直接搜索可以得到暴力分,因为所有和牌方案一共只有一千万左右,稍微优化一下数据 ...

  3. 【BZOJ5503】&lbrack;GXOI&sol;GZOI2019&rsqb;宝牌一大堆(动态规划)

    [BZOJ5503][GXOI/GZOI2019]宝牌一大堆(动态规划) 题面 BZOJ 洛谷 题解 首先特殊牌型直接特判. 然后剩下的部分可以直接\(dp\),直接把所有可以存的全部带进去大力\(d ...

  4. &lbrack;LOJ3084&rsqb;&lbrack;GXOI&sol;GZOI2019&rsqb;宝牌一大堆——DP

    题目链接: [GXOI/GZOI2019]宝牌一大堆 求最大值容易想到$DP$,但如果将$7$种和牌都考虑进来的话,$DP$状态不好设,我们将比较特殊的七小对和国士无双单独求,其他的进行$DP$. 观 ...

  5. &lbrack;GXOI&sol;GZOI2019&rsqb;宝牌一大堆&lpar;dp&rpar;

    luogu     bzoj 这个麻将题还算挺友善的,比隔壁zjoi的要好得多... 比较正常的做法是五维dp 但事实上六维dp也是完全不会被卡的 七对子选权值最高的七个,国士无双直接$13^2$暴力 ...

  6. 题解 P5301 【&lbrack;GXOI&sol;GZOI2019&rsqb;宝牌一大堆】

    这道题除了非常恶心以外也没有什么非常让人恶心的地方 当然一定要说有的话还是有的,就是这题和咱 ZJOI 的 mahjong 真的是好像的说~ 于是就想说这道题出题人应该被 锕 掉 noteskey 整 ...

  7. &lbrack;luogu 5301&rsqb;&lbrack;bzoj 5503&rsqb; &lbrack;GXOI&sol;GZOI2019&rsqb; 宝牌一大堆

    题面 好像ZJOI也考了一道麻将, 这是要发扬中华民族的赌博传统吗??? 暴搜都不会打, 看到题目就自闭了, 考完出来之后看题解, \(dp\), 可惜自己想不出来... 对于国士无双(脑子中闪过了韩 ...

  8. &lbrack;GXOI&sol;GZOI2019&rsqb;宝牌一大堆

    感觉比ZJOI的麻将要休闲很多啊. 这个题就是一个最优化问题,没有面子的特殊牌型可以直接用复杂度较低的贪心判掉. 有面子的话就是一个经典dp.(曾经还在ZJOI写过这个毒瘤东西 大概就是存一下对子,面 ...

  9. &lbrack;GX&sol;GZOI2019&rsqb;宝牌一大堆(DP)

    出这种麻将题有意思吗? 乍看很难实则很水,就是麻将式DP,想必大家很熟悉了吧.首先把“国士无双”和“七对子”两种牌型判掉,然后观察牌胡的形式,发现每多一张牌实际上就是把1个面子变成1个杠子,然后可以直 ...

随机推荐

  1. JSP之-&gt&semi;初识JSP

    JSP 引用百度百科的介绍: JSP(Java Server Pages)是由Sun Microsystems公司倡导.许多公司参与一起建立的一种动态网页技术标准.JSP技术有点类似ASP技术,它是在 ...

  2. ytu 1067&colon; 顺序排号(约瑟夫环)

    1067: 顺序排号 Time Limit: 1 Sec  Memory Limit: 128 MBSubmit: 31  Solved: 16[Submit][Status][Web Board] ...

  3. 总结&amp&semi;记录

    一.Git(linux命令) 1.tar  压缩/解压 -c 建立一个压缩文件(create) -x 解压一个压缩文件 -t 查看tarfile中文件 -z 是否具有gzip的属性?是否需要用gzip ...

  4. 【Java基础】Java内部类

    什么是内部类 把类定义在其他类的内部,这个类就被称为内部类. 内部类的分类 内部类分为两种,分别为成员内部类和局部内部类: 成员内部类:和成员变量和成员方法定义在同级 局部内部类:和局部变量定义在同级 ...

  5. jboss学习 - vfs---转载

    jboss的VFS是为了解决什么问题,他为什么有用呢 在jboss中有很多类似的资源操作的代码都分散在程序的各个地方,大多数情况下代码首先确定操作的资源的类型,比如是文件或者是文件夹,通过URL加载的 ...

  6. js数组对象方法

  7. java 程序编写规则(自己总结)

    1.命名规范 (1)所有的标示符都只能用ASCⅡ字母(A-Z或a-z).数字(0-9)和下划线"_". (2)类名是一个名词,采用大小写混合的方式,每个单词的首字母大写.例如:Us ...

  8. 学习java接口知识

    学习java接口知识 //一个类最多只能有一个直接的父类.但是有多个间接的父类. java是单继承. class ye_01{ String name; } class fu_01 extends y ...

  9. 【转】用emWin进度条控件做个表盘控件&comma;效果不错

    @2018-08-09 用emWin进度条控件做个表盘控件,效果不错

  10. Redis list 数据类型

    lpush()先进后出  //从头部加入元素   //栈      lrange 元素集合   0    -1 lpop  从list头部删除元素,并返回删除元素 rpush()先进先出 //从尾部加 ...