「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的子矩阵的个数 子矩阵怎么求可以记录每个位置 ...
随机推荐
- AntDesign vue学习笔记(八)Table服务端分页使用
本文是AntDesign后端分页方法 1.设置pagination <a-table :columns="columns" :dataSource="data&qu ...
- ipv4的ip字符串转化为int型
要求: 将现有一个ipv4的ip字符串(仅包含数字,点,空格), 其中数字和点之间的空格(至多一个)是合法的,比如“12 .3. 4 .62”,其他情况均为非法地址.写一个函数将ipv4地址字符串转化 ...
- day58——模板继承、组件、自定义标签和过滤器、inclusion_tag、静态文件配置、url别名和反向解析、url命名空间
day58 模板相关 模板继承(母版继承) 1. 创建一个xx.html页面(作为母版,其他页面来继承它使用) 2. 在母版中定义block块(可以定义多个,整个页面任意位置) {% block co ...
- Java的常用API之Date类简介
Data类 java.util.Date:表示日期和时间的类类Date 表示特定的瞬间,精确到毫秒.毫秒:千分之一秒 1000毫秒=1秒 把日期转换成毫秒: 当前的日期:2019-07-18 时间原点 ...
- SQL系列(十三)—— 关于表的DDL
前面的文章一直都在讲述关于DML方面的SQL Statement.这篇文章来说说表方面的DDL: CREATE 创建表 ALTER 修改表 DROP 删除表 CREATE 1.语法 CREATE TA ...
- 一个 Java 正则表达式例子
今天在项目里看到用 Python 正则表达式的时候,用到 group,没有仔细看.正好学习 Java 正则表达式,对 group 多留意了一下. 上代码: import java.util.regex ...
- 《即时消息技术剖析与实战》学习笔记1——IM系统的架构
一.IM的应用场景 聊天.直播.在线客服.物联网等所有需要实时互动.高实时性的场景,都需要应用到 IM 技术.
- mysql 5.7 修改root密码允许远程连接
1.修改root密码(其他用户类似) 试过网上看的一些 在mysql数据库执行 update user set password='新密码' where user='root' 执行说找不到字段, ...
- java面试经常涉及到的
需要掌握的Java知识点: 1 基本数据类型.循环控制.String类型的使用.数组.类和对象.接口和抽象类.面向对象三大特征.异常处理.集合类(List.Map.Set) 2 能够熟练使用Sprin ...
- HeRaNO's NOIP CSP Round Day 2 T3 ginkgo
睡醒后我第一眼:这不主席树裸题吗? 先统计dfs序,把树上问题转化为区间问题 区间大于等于某个数的个数...主席树模板? #include<bits/stdc++.h> #define r ...