这道题除了非常恶心以外也没有什么非常让人恶心的地方
当然一定要说有的话还是有的,就是这题和咱 ZJOI 的 mahjong 真的是好像的说~
于是就想说这道题出题人应该被 锕 掉
noteskey
整体的思路就是特判国士无双和七对子,然后 dp 搞普通的胡牌
dp 状态设计和楼上大佬说的一样,就是用一个五维的 \(f[i][j][k][l][p]\) 表示当前处理了前 i 种类型的牌,存在 j 个 面子/杠子 ,以 i-1 开头的顺子要选 k 个,以 i 开头的面子要选 l 个,以及当前是否有 雀头 (用 p 表示)
然后转移就非常的暴力了,反正这里的数据范围也比较小,枚举下状态转移就好了
总的来说就是道 语文 + 码农 + dp 题,虽说没什么思维难度但我不见得能想出来
watch out
这题的字符串读入还是比较毒瘤的...要稍微注意一下不然可能会出事
code
这压行是同样的味道呢~
//by Judge
#include<bits/stdc++.h>
#define Rg register
#define fp(i,a,b) for(Rg int i=(a),I=(b)+1;i<I;++i)
#define ll long long
using namespace std;
#ifndef Judge
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
char buf[1<<21],*p1=buf,*p2=buf;
inline bool cmax(ll& a,ll b){return a<b?a=b,1:0;}
inline int read(){ int x=0,f=1; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=x*10+c-'0'; return x*f;
} inline void reads(string& s){ char c=getchar();
for(;!isalpha(c)&&!isdigit(c);c=getchar()); s="";
for(;isalpha(c)||isdigit(c);c=getchar()) s+=c;
} char sr[1<<21],z[20];int CCF=-1,Z;
inline void Ot(){fwrite(sr,1,CCF+1,stdout),CCF=-1;}
inline void print(ll x,char chr='\n'){
if(CCF>1<<20)Ot();if(x<0)sr[++CCF]=45,x=-x;
while(z[++Z]=x%10+48,x/=10);
while(sr[++CCF]=z[Z],--Z);sr[++CCF]=chr;
} int t,cnt,a[41],b[41],C[5][5]; ll f[41][5][3][3][2],tp[41];
int gs[14]={0,1,9,10,18,19,27,28,29,30,31,32,33,34}; string c;
inline int id(){ if(c[0]=='B') return 34;
if(c[0]=='E') return 28; if(c[0]=='S') return 29; if(c[0]=='W') return 30;
if(c[0]=='N') return 31; if(c[0]=='Z') return 32; if(c[0]=='F') return 33;
if(c[1]=='m') return c[0]-48; if(c[1]=='p') return c[0]-39; return c[0]-30;
}
int main(){ C[0][0]=1;
fp(i,1,4){ C[i][0]=1;
fp(j,1,i) C[i][j]=C[i-1][j-1]+C[i-1][j];
}
fp(T,1,read()){
memset(a,0,sizeof a);
memset(b,0,sizeof b);
memset(f,0,sizeof f);
while(1){ reads(c);
if(c[0]=='0') break;
else ++a[id()];
}
while(1){ reads(c);
if(c[0]=='0') break;
else b[id()]=1;
}
fp(i,1,34) a[i]=4-a[i];
ll ans=0;
fp(i,1,13){ ll tmp=1; //枚举出现两次的牌
fp(j,1,13) //枚举 13 种牌
if(i==j)
if(a[gs[j]]<2) tmp=0; //如果数量不够就让 tmp=0
else tmp*=C[a[gs[j]]][2]*(b[gs[j]]?4:1); //否则加贡献
else
if(a[gs[j]]<1) tmp=0;
else tmp*=C[a[gs[j]]][1]*(b[gs[j]]?2:1);
cmax(ans,tmp*13);
}
cnt=0;
fp(i,1,34) if(a[i]>=2) tp[++cnt]=C[a[i]][2]*(b[i]?4:1);
if(cnt>=7){ //如果牌数大于等于 2 的不止 7 张就可以构成七对子
sort(tp+1,tp+1+cnt); ll tmp=1; //选出权最大的 7 种牌
fp(i,cnt-6,cnt) tmp*=tp[i]; //累乘贡献
cmax(ans,tmp*7);
}
f[0][0][0][0][0]=1; //初始化边界
fp(i,0,33) fp(j,0,4) for(Rg int k=0;k<3&&j+k<=4;++k){
if(k>=1&&(i==9||i==18||i>=27)) break; //不合法开头无法构成顺子
for(Rg int l=0;l<3&&j+k+l<=4;++l){
if(l>=1&&(i==9||i==18||i==27)) break;
if(f[i][j][k][l][0]||f[i][j][k][l][1]) fp(u,k+l,a[i+1]){
ll tmp=C[a[i+1]][u]*(b[i+1]?(1<<u):1); //计算贡献
// 四种转移
if(j+u<=4&&u-k-l<3)
cmax(f[i+1][j+k][l][u-k-l][0],f[i][j][k][l][0]*tmp),
cmax(f[i+1][j+k][l][u-k-l][1],f[i][j][k][l][1]*tmp);
if(u-k-l-2>=0&&j+u-2<=4)
cmax(f[i+1][j+k][l][u-k-l-2][1],f[i][j][k][l][0]*tmp);
if(u-k-l-3>=0&&j+u-2<=4)
cmax(f[i+1][j+k+1][l][u-k-l-3][0],f[i][j][k][l][0]*tmp),
cmax(f[i+1][j+k+1][l][u-k-l-3][1],f[i][j][k][l][1]*tmp);
if(u==4&&!k&&!l&&j<=3)
cmax(f[i+1][j+1][0][0][0],f[i][j][k][l][0]*tmp),
cmax(f[i+1][j+1][0][0][1],f[i][j][k][l][1]*tmp);
}
}
}
cmax(ans,f[34][4][0][0][1]),print(ans);
} return Ot(),0;
}
题解 P5301 【[GXOI/GZOI2019]宝牌一大堆】的更多相关文章
-
P5301 [GXOI/GZOI2019]宝牌一大堆
题目地址:P5301 [GXOI/GZOI2019]宝牌一大堆 这里是官方题解(by lydrainbowcat) 部分分 直接搜索可以得到暴力分,因为所有和牌方案一共只有一千万左右,稍微优化一下数据 ...
-
【题解】Luogu P5301 [GXOI/GZOI2019]宝牌一大堆
原题传送门 首先先要学会麻将,然后会发现就是一个暴力dp,分三种情况考虑: 1.非七对子国士无双,设\(dp_{i,j,k,a,b}\)表示看到了第\(i\)种牌,一共有\(j\)个\(i-1\)开头 ...
-
luogu P5301 [GXOI/GZOI2019]宝牌一大堆
传送门 wdnm又是打麻将 首先国土无双可以直接枚举哪种牌用了\(2\)次算贡献,然后\(7\)个对子可以把每种牌的对子贡献排序,取最大的\(7\)个,剩下的牌直接暴力枚举是不行的,考虑dp,设\(f ...
-
【BZOJ5503】[GXOI/GZOI2019]宝牌一大堆(动态规划)
[BZOJ5503][GXOI/GZOI2019]宝牌一大堆(动态规划) 题面 BZOJ 洛谷 题解 首先特殊牌型直接特判. 然后剩下的部分可以直接\(dp\),直接把所有可以存的全部带进去大力\(d ...
-
[LOJ3084][GXOI/GZOI2019]宝牌一大堆——DP
题目链接: [GXOI/GZOI2019]宝牌一大堆 求最大值容易想到$DP$,但如果将$7$种和牌都考虑进来的话,$DP$状态不好设,我们将比较特殊的七小对和国士无双单独求,其他的进行$DP$. 观 ...
-
[GXOI/GZOI2019]宝牌一大堆(dp)
luogu bzoj 这个麻将题还算挺友善的,比隔壁zjoi的要好得多... 比较正常的做法是五维dp 但事实上六维dp也是完全不会被卡的 七对子选权值最高的七个,国士无双直接$13^2$暴力 ...
-
[luogu 5301][bzoj 5503] [GXOI/GZOI2019] 宝牌一大堆
题面 好像ZJOI也考了一道麻将, 这是要发扬中华民族的赌博传统吗??? 暴搜都不会打, 看到题目就自闭了, 考完出来之后看题解, \(dp\), 可惜自己想不出来... 对于国士无双(脑子中闪过了韩 ...
-
[GXOI/GZOI2019]宝牌一大堆
感觉比ZJOI的麻将要休闲很多啊. 这个题就是一个最优化问题,没有面子的特殊牌型可以直接用复杂度较低的贪心判掉. 有面子的话就是一个经典dp.(曾经还在ZJOI写过这个毒瘤东西 大概就是存一下对子,面 ...
-
[GX/GZOI2019]宝牌一大堆(DP)
出这种麻将题有意思吗? 乍看很难实则很水,就是麻将式DP,想必大家很熟悉了吧.首先把“国士无双”和“七对子”两种牌型判掉,然后观察牌胡的形式,发现每多一张牌实际上就是把1个面子变成1个杠子,然后可以直 ...
随机推荐
-
CentOS网卡配置文件
[root@xaiofan ~]# cat /etc/sysconfig/network-scripts/ifcfg-eth0 DEVICE=eth0TYPE=EthernetONBOOT=yesNM ...
-
java 反射机制探究
一 反射机制操作类的成员变量 二 操作类的方法 三 利用反射实例化类 四 利用反射访问一个类的私有成员 五 利用反射覆盖数据对象的toString 方法
-
安装npm及cnpm(Windows)
[工具官网] Node.js : http://nodejs.cn/ 淘宝NPM: https://npm.taobao.org/ [安装步骤] 一.安装node.js 1.前往node.js官网下载 ...
-
ABP项目概述
在系统性介绍整个ABP框架之前,我们首先需要对ABP框架有一个大概的了解,ABP框架的全称是:Asp.Net Boilerplate Project(即Asp.Net 的样板项目)顾名思义就是能够通过 ...
-
利用python实现两个文件夹的同步
其实无论windows还是Linux,简单地去实现两个两个文件夹的同步只需系统自带的复制命令加参数就可以了. WINDOWS : xcopy 源文件夹\* 目标文件夹 /s /e /y Linux : ...
-
vsftp设置不同用户登录ftp的根目录不同
创建三个用户 [root@SHM-Storage-EF ~]# useradd kids [root@SHM-Storage-EF ~]# useradd mini [root@SHM-Storage ...
-
springboot中generator相关配置文件
generator.properties # jdbc jdbc.driverClass = com.mysql.jdbc.Driver jdbc.url = jdbc:mysql://localho ...
-
一个jquery-ajax post例子ajax 登陆
index.html文件 <html> <head> <meta http-equiv="Content-Type" content="te ...
-
16、xtrabackup 增量备份及恢复
备份命令如下 备份命令如下 全量备份 # innobackupex -p123123 /backup # ls /backup 2017-04-08_13-36-11 增量备份或差量备份 # inn ...
-
mv 命令 简要
1.mv test.txt test1.txt 给文件重命名 2.mv test.txt aaDir 将test.txt文件移动到aaDir文件夹中 3.mv -t /hom ...