「GXOI / GZOI2019」宝牌一大堆 (DP)
题意
题解
可以发现「七对子」 和 「国士无双」直接暴力就行了。
唯一的就是剩下的"3*4+2"。
考试的时候写了个爆搜剪枝,开了O2有50pts。写的时候发现可以DP,但是没写。
然后下来写了发现就4个转移。。。
用\(dp[i][j][k][a][b][c]\)表示当考虑前\(i\)张牌,有\(j\)个雀头,\(k\)个面子,\(i-2\)用了\(a\)张,\(i-1\)用了\(b\)张,\(i\)用了\(c\)张时,前\(i-3\)张牌的最大分数。
注意这里是"前\(i-3\)张牌的最大分数",也就是没有计算\(a,b,c\)这最后\(3\)种牌的贡献。
有个性质就是杠子一定不会选,因为选杠子一定劣于面子。
因为\(C(4,4)=1<C(4,3)=4\),就算这张牌是宝牌,杠子的贡献是\(C(4,4)*2^4<C(4,3)*2^3\)
所以我们没有考虑杠子。
上代码
CODE
luogu上开了O2才过
#include <bits/stdc++.h>
using namespace std;
inline int getid(char *s) {
if(isdigit(s[0])) {
int re = s[0]-'0';
if(s[1] == 'm') return re;
if(s[1] == 'p') return 9+re;
if(s[1] == 's') return 18+re;
}
if(s[0] == 'E') return 28;
if(s[0] == 'S') return 29;
if(s[0] == 'W') return 30;
if(s[0] == 'N') return 31;
if(s[0] == 'Z') return 32;
if(s[0] == 'B') return 33;
if(s[0] == 'F') return 34;
}
typedef long long LL;
int cnt[50], bel[50];
LL ans, c[5][5], pw6[10];
bool bao[50];
int arr13[14] = { 0, 1, 9, 10, 18, 19, 27, 28, 29, 30, 31, 32, 33, 34 }; //指定的13张牌的编号
void solve13() {
bool flg = 1;
for(int i = 1; i <= 13; ++i) flg &= bool(cnt[arr13[i]]);
if(flg) {
LL now = 13;
for(int i = 1; i <= 13; ++i)
now = now * c[cnt[arr13[i]]][1] * (bao[arr13[i]] ? 2 : 1);
for(int i = 1; i <= 13; ++i)
ans = max(ans, now / c[cnt[arr13[i]]][1] * c[cnt[arr13[i]]][2] * (bao[arr13[i]] ? 2 : 1));
}
}
void dfs(int i, int j, LL now) { //暴力枚举七对子
if(j == 7) { ans = max(now, ans); return; }
if(i > 34) return;
LL tmp = now*pw6[7-j]*(1ll<<((7-j)<<1)); //剪枝,预估之后的最大值,如果小于等于当前答案就不用了搜下去了
if(tmp <= ans) return;
if(cnt[i] >= 2) {
cnt[i] -= 2;
dfs(i+1, j+1, now*c[cnt[i]+2][2]*(bao[i]?4:1));
cnt[i] += 2;
}
if(tmp <= ans) return;
dfs(i+1, j, now);
}
void solve7() { dfs(1, 0, 7); }
LL dp[36][2][5][5][5][5];
inline void upd(LL &x, LL y) { x = y > x ? y : x; }
inline int calc(int i, int j) { return i > 0 ? c[cnt[i]][j] * (bao[i] ? (1<<j) : 1) : 1; } //计算i选j张的贡献
void solve() {
memset(dp, 0, sizeof dp);
dp[1][0][0][0][0][0] = 1;
for(int i = 1; i <= 34; ++i)
for(int j = 0; j < 2; ++j)
for(int k = 0; k <= 4; ++k)
for(int a = 0; a <= 4; ++a)
for(int b = 0; b <= 4; ++b)
for(int c = 0; c <= 4; ++c) {
LL val = dp[i][j][k][a][b][c];
if(val) {
upd(dp[i+1][j][k][b][c][0], val * calc(i-2, a));
if(!j && cnt[i]-c >= 2)
upd(dp[i][j+1][k][a][b][c+2], val);
if(k<4 && cnt[i]-c >= 3)
upd(dp[i][j][k+1][a][b][c+3], val);
if(k<4 && bel[i] && i>2 && bel[i]==bel[i-2] && cnt[i]-c >= 1 && cnt[i-1]-b >= 1 && cnt[i-2]-a >= 1)
upd(dp[i][j][k+1][a+1][b+1][c+1], val);
}
}
for(int a = 0; a <= 4; ++a)
for(int b = 0; b <= 4; ++b)
for(int c = 0; c <= 4; ++c) //最后答案算上a,b,c
upd(ans, dp[34][1][4][a][b][c] * calc(32, a) * calc(33, b) * calc(34, c));
}
int main () {
//freopen("doraippai.in", "r", stdin);
// freopen("doraippai.out", "w", stdout);
for(int i = 1; i <= 9; ++i) bel[i] = 1;
for(int i = 10; i <= 18; ++i) bel[i] = 2;
for(int i = 19; i <= 27; ++i) bel[i] = 3;
c[0][0] = 1;
for(int i = 1; i <= 4; ++i) {
c[i][0] = c[i][i] = 1;
for(int j = 1; j < i; ++j)
c[i][j] = c[i-1][j-1] + c[i-1][j];
}
pw6[0] = 1;
for(int i = 1; i <= 7; ++i) pw6[i] = 6ll * pw6[i-1];
int T; scanf("%d", &T); while(T--) {
for(int i = 1; i <= 34; ++i)
cnt[i] = 4, bao[i] = 0;
char s[5];
while(scanf("%s", s), s[0] != '0') {
int num = getid(s);
--cnt[num];
}
while(scanf("%s", s), s[0] != '0') {
int num = getid(s);
bao[num] = 1;
}
ans = 0;
solve13();
solve7();
solve();
printf("%lld\n", ans);
}
}
「GXOI / GZOI2019」宝牌一大堆 (DP)的更多相关文章
- LOJ#3084. 「GXOI / GZOI2019」宝牌一大堆(递推)
题面 传送门 题解 为什么又是麻将啊啊啊!而且还是我最讨厌的爆搜类\(dp\)-- 首先国士无双和七对子是可以直接搞掉的,关键是剩下的,可以看成\(1\)个雀头加\(4\)个杠子或面子 直接\(dp\ ...
- 「GXOI / GZOI2019」简要题解
「GXOI / GZOI2019」简要题解 LOJ#3083. 「GXOI / GZOI2019」与或和 https://loj.ac/problem/3083 题意:求一个矩阵的所有子矩阵的与和 和 ...
- LOJ#3083.「GXOI / GZOI2019」与或和_单调栈_拆位
#3083. 「GXOI / GZOI2019」与或和 题目大意 给定一个\(N\times N\)的矩阵,求所有子矩阵的\(AND(\&)\)之和.\(OR(|)\)之和. 数据范围 \(1 ...
- Loj #3085. 「GXOI / GZOI2019」特技飞行
Loj #3085. 「GXOI / GZOI2019」特技飞行 题目描述 公元 \(9012\) 年,Z 市的航空基地计划举行一场特技飞行表演.表演的场地可以看作一个二维平面直角坐标系,其中横坐标代 ...
- 【LOJ】#3088. 「GXOI / GZOI2019」旧词
LOJ#3088. 「GXOI / GZOI2019」旧词 不懂啊5e4感觉有点小 就是离线询问,在每个x上挂上y的询问 然后树剖,每个节点维护轻儿子中已经被加入的点的个数个数乘上\(dep[u]^{ ...
- 【LOJ】#3087. 「GXOI / GZOI2019」旅行者
LOJ#3087. 「GXOI / GZOI2019」旅行者 正着求一遍dij,反着求一遍,然后枚举每条边,从u到v,如果到u最近的点和v能到的最近的点不同,那么可以更新答案 没了 #include ...
- 【LOJ】#3086. 「GXOI / GZOI2019」逼死强迫症
LOJ#3086. 「GXOI / GZOI2019」逼死强迫症 这个就是设状态为\(S,j\)表示轮廓线为\(S\),然后用的1×1个数为j 列出矩阵转移 这样会算重两个边相邻的,只要算出斐波那契数 ...
- 【LOJ】#3085. 「GXOI / GZOI2019」特技飞行
LOJ#3085. 「GXOI / GZOI2019」特技飞行 这显然是两道题,求\(C\)是一个曼哈顿转切比雪夫后的线段树扫描线 求\(AB\),对向交换最大化和擦身而过最大化一定分别为最大值和最小 ...
- 【LOJ】#3083. 「GXOI / GZOI2019」与或和
LOJ#3083. 「GXOI / GZOI2019」与或和 显然是先拆位,AND的答案是所有数字为1的子矩阵的个数 OR是所有的子矩阵个数减去所有数字为0的子矩阵的个数 子矩阵怎么求可以记录每个位置 ...
随机推荐
- js实现对上传图片的路径转成base64编码,并且对图片进行压缩,实现预览功能1
参考 https://blog.csdn.net/qq_31965515/article/details/82975381 https://www.cnblogs.com/zhangdiIT/p/78 ...
- 在Apache中安装php5.6 & php7.3
1.下载 httpd-2.4.41-win64-VC15.zip.php5.6 + vc11. php7.3 + vc14-16 2.配置httpd,在 httpd.conf L180 添加如下 ...
- cmdb知识总结
cmdb面试 1.paramiko模块的作用与原理 2.cmdb是什么 3.为什么要开发CMDB? 4.你们公司有多少台服务器?物理机?虚拟机? 5.你的CMDB是如何实现的? 6.CMDB都用到了哪 ...
- AD常用快捷键
元器件翻转 : 空格 按住shift拖动元器件实现自动编号 取消布线 : 工具(Tools)取消布线(Un_Route)全部(AII) 栅格变为点阵 : 按ctrl+G——打开cartesian Gr ...
- Orleans 3.0 为我们带来了什么(转载)
以下为本篇文章的 作者: 艾心 出处: https://www.cnblogs.com/edison0621/ 原文:https://devblogs.microsoft.com/dotnet/orl ...
- System.ArgumentException:路由集合中已存在名为“XXX”的路由。路由名称必须唯一。
软件环境:Visual Studio 2017 + MVC4 + EF6 问题描述:System.ArgumentException:路由集合中已存在名为“XXX”的路由.路由名称必须唯一. 解决办法 ...
- 第一阶段:Java基础 1.JAVA开发介绍---2. JVM、JRE、JDK之间的关系
JDK :英文名称(Java Development Kit),Java 开发工具包,是针对 Java 开发员的产品.jdk 是整个 Java 开发的核心,包括了Java运行环境JRE.Java工具和 ...
- 指针总结指向const的指针、const指针、指向const指针的const指针
指针的一些总结 const与指针 指向const的指针指的是指针指向的数据是常量,不可以被修改,但指针变量本身可以被修改,如const int *p:严格说不能用指针间接修改指向的数据,但该变量可 ...
- Python面向对象继承案例
面向对象三大特性 封装 根据 职责 将 属性 和 方法 封装 到一个抽象的 类 中 继承 实现代码的重用,相同的代码不需要重复的编写 多态 不同的对象调用相同的方法,产生不同的执行结果,增加代码的灵活 ...
- JavaScript之变量(声明、解析、作用域)
声明(创建) JavaScript 变量 在 JavaScript 中创建变量通常称为"声明"变量. 一.我们使用 var 关键词来声明变量: var carname; 变量声明之 ...