「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的子矩阵的个数 子矩阵怎么求可以记录每个位置 ...
随机推荐
- 【Appium + Python + WebviewH5】之微信小程序自动化测试
进行调试,打开X5: http://debugmm.qq.com/?forcex5=true http://debugx5.qq.com http://debugtbs.qq.com 一般前两个就可以 ...
- 百度前端技术学院task16源代码
欢迎访问我的github:huanshen 做这道题目的时候遇到了很多困难. 1.怎么给空对象添加数据,愣是不知道从哪里下手:遍历对象,一个个输出操作: 2.中英文的正则表达式不知道,赶紧去百度: 3 ...
- sqlalchemy 配合bootstrap-table实现后台分页
创建公共的mysql连接函数 def db_session(): db_config='mysql+mysqldb://'+ mysqluser + ':' + mysqlpassword+'@'+m ...
- sql 语句中定义的变量不能和 sql关键字冲突
sql 语句中定义的变量不能和 sql关键字冲突 from bs_email_account account LEFT JOIN bs_group_info gp ON account.group_i ...
- 整理:WPF中Binding的几种写法
原文:整理:WPF中Binding的几种写法 目的:整理WPF中Bind的写法 <!--绑定到DataContext--> <Button Content="{Bindin ...
- 获取html 中的内容 将前台的数据获取到后台 用 jquery 生成一个 form表单 提交数据
使用js创建一个form表单 ,使用post上传到后台中 下面是代码.在获取html内容的时候使用了js节点来获取内容. parent:父节点.上一级的节点 siblings:兄弟节点.同一级别的节点 ...
- java 泛型和object比较
引言 我们使用object和泛型做形参,都是为了让这个方法能接收更多类型的对象,让程序变得更健壮,代码复用率更高.当我们回看自己写的代码时会发现,好像使用泛型的地方使用object也可以,使用obje ...
- 在浏览器中输入 url 地址到显示主页的过程
总体来说分为以下几个过程:1. DNS 解析2. TCP 连接3. 发送 HTTP 请求4. 服务器处理请求并返回 HTTP 报文5. 浏览器解析渲染页面6. 连接结束
- Java虚拟机是怎么new的对象?
本文涉及:Java中的new命令之后发生的事 类加载检查 java虚拟机在遇到一条 new 指令时,首先会检查是否能在常量池中定位到这个类的符号引用,并且是否已被加载过.解析和初始化过.如果没有,那必 ...
- 下一代微服务-ServiceMesh
1.简介 系统服务化之后,服务间通信需要关注什么? 服务发现.负载均衡.路由.流控.通信可靠性.弹性.安全.监控.日志 API网关可以集中式的管理这些功能,但是会出现单点故障,并且实现起来网关会变得越 ...