感觉比ZJOI的麻将要休闲很多啊。

这个题就是一个最优化问题,没有面子的特殊牌型可以直接用复杂度较低的贪心判掉。

有面子的话就是一个经典dp。(曾经还在ZJOI写过这个毒瘤东西

大概就是存一下对子,面子,杠子的个数,再记一下上两个位置剩余的牌的个数,转移非常简单。

写起来挺爽的。

  1. #include<bits/stdc++.h>
  2. #define N 55
  3. #define eps 1e-7
  4. #define inf 1e18+7
  5. #define db double
  6. #define ll long long
  7. #define ldb long double
  8. using namespace std;
  9. inline ll read()
  10. {
  11. char ch=0;
  12. ll x=0,flag=1;
  13. while(!isdigit(ch)){ch=getchar();if(ch=='-')flag=-1;}
  14. while(isdigit(ch)){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
  15. return x*flag;
  16. }
  17. map<string,ll>mp;
  18. bool h[N],flag[N],chk[N][N][N];
  19. ll tot,ans,a[N],b[N],cnt[N],C[N][N];
  20. void prepare()
  21. {
  22. //万
  23. mp["1m"]=++tot;mp["2m"]=++tot;mp["3m"]=++tot;
  24. mp["4m"]=++tot;mp["5m"]=++tot;mp["6m"]=++tot;
  25. mp["7m"]=++tot;mp["8m"]=++tot;mp["9m"]=++tot;
  26. //筒
  27. mp["1p"]=++tot;mp["2p"]=++tot;mp["3p"]=++tot;
  28. mp["4p"]=++tot;mp["5p"]=++tot;mp["6p"]=++tot;
  29. mp["7p"]=++tot;mp["8p"]=++tot;mp["9p"]=++tot;
  30. //索
  31. mp["1s"]=++tot;mp["2s"]=++tot;mp["3s"]=++tot;
  32. mp["4s"]=++tot;mp["5s"]=++tot;mp["6s"]=++tot;
  33. mp["7s"]=++tot;mp["8s"]=++tot;mp["9s"]=++tot;
  34. //其它
  35. mp["E"]=++tot;mp["S"]=++tot;mp["W"]=++tot;mp["N"]=++tot;
  36. mp["Z"]=++tot;mp["B"]=++tot;mp["F"]=++tot;
  37. //组合数
  38. for(ll i=0;i<=10;i++)
  39. {
  40. C[i][0]=1;
  41. for(ll j=1;j<=i;j++)C[i][j]=C[i-1][j-1]+C[i-1][j];
  42. }
  43. //预处理可以凑面子的位置
  44. for(ll i=1;i<=27;i++)h[i]=true;
  45. h[1]=h[2]=h[10]=h[11]=h[19]=h[20]=false;
  46. //预处理合法状态
  47. chk[1][4][0]=chk[1][3][1]=chk[1][2][2]=chk[1][1][3]=true;
  48. for(ll i=1;i>=0;i--)for(ll j=4;j>=0;j--)for(ll k=4;k>=0;k--)
  49. if(chk[i][j][k])
  50. {
  51. if(i)chk[i-1][j][k]=true;
  52. if(j)chk[i][j-1][k]=true;
  53. if(k)chk[i][j][k-1]=true;
  54. }
  55. }
  56. void clear()
  57. {
  58. ans=0;
  59. for(ll i=0;i<=4;i++)a[i]=b[i]=0;
  60. for(ll i=1;i<=tot;i++)cnt[i]=4,flag[i]=false;
  61. }
  62. ll ksm(ll x,ll k)
  63. {
  64. ll ans=1;
  65. while(k){if(k&1)ans*=x;k>>=1;x*=x;}
  66. return ans;
  67. }
  68. ll work1()//七对子
  69. {
  70. ll k,now=0,ans=7;
  71. k=min(a[4],7-now);now+=k;ans*=ksm(24,k);
  72. k=min(a[3],7-now);now+=k;ans*=ksm(12,k);
  73. k=min(b[4],7-now);now+=k;ans*=ksm(6,k);
  74. k=min(a[2],7-now);now+=k;ans*=ksm(4,k);
  75. k=min(b[3],7-now);now+=k;ans*=ksm(3,k);
  76. k=min(b[2],7-now);now+=k;ans*=ksm(1,k);
  77. k=min(a[4],7-now);now+=k;ans/=ksm(6,k);ans*=ksm(4,k);
  78. k=min(b[4],7-now);now+=k;ans/=ksm(6,k);ans*=ksm(1,k);
  79. if(now==7)return ans;else return -inf;
  80. }
  81. ll work2()//国士无双
  82. {
  83. bool ok=false;
  84. ll p[20],now=13,ans=0;
  85. p[1]=1;p[2]=9;p[3]=10;p[4]=18;p[5]=19;p[6]=27;
  86. p[7]=28;p[8]=29;p[9]=30;p[10]=31;p[11]=32;p[12]=33;p[13]=34;
  87. for(ll i=1;i<=13;i++)
  88. {
  89. ll x=p[i];
  90. if(!cnt[x])return -inf;
  91. if(cnt[x]>=2)ok=true;
  92. now*=cnt[x];if(flag[x])now*=2;
  93. }
  94. if(!ok)return -inf;
  95. for(ll i=1;i<=13;i++)
  96. {
  97. ll x=p[i];
  98. if(cnt[x]==2)ans=max(ans,(now/2)*1*(flag[x]?2:1));
  99. if(cnt[x]==3)ans=max(ans,(now/3)*3*(flag[x]?2:1));
  100. if(cnt[x]==4)ans=max(ans,(now/4)*6*(flag[x]?2:1));
  101. }
  102. return ans;
  103. }
  104. ll dp[2][5][4][5][5][5],DP[2][5][4][5][5][5];
  105. void update(ll &x,ll k){x=max(x,k);}
  106. ll work3()//各种杠子+面子+雀头
  107. {
  108. memset(DP,-1,sizeof(DP));
  109. DP[0][0][0][cnt[1]][0][0]=1;
  110. for(ll i=1;i<=tot;i++)
  111. {
  112. ll lx=cnt[i],ly=(i<=1)?0:cnt[i-1],lz=(i<=2)?0:cnt[i-2];
  113. for(ll a=0;a<=1;a++)for(ll b=0;b<=4;b++)for(ll c=0;c<=3;c++)if(chk[a][b][c])
  114. for(ll x=0;x<=4;x++)for(ll y=0;y<=4;y++)for(ll z=0;z<=4;z++)
  115. dp[a][b][c][x][y][z]=DP[a][b][c][x][y][z],DP[a][b][c][x][y][z]=-1;
  116. for(ll a=0;a<=1;a++)for(ll b=0;b<=4;b++)for(ll c=0;c<=3;c++)if(chk[a][b][c])
  117. for(ll x=0;x<=lx;x++)for(ll y=0;y<=ly;y++)for(ll z=0;z<=lz;z++)
  118. {
  119. ll o=dp[a][b][c][x][y][z];if(o<=0)continue;
  120. if(x>=2&&a!=1)update(dp[a+1][b][c][x-2][y][z],o);
  121. if(x>=3&&b!=4)update(dp[a][b+1][c][x-3][y][z],o);
  122. if(x>=4&&c!=3)update(dp[a][b][c+1][x-4][y][z],o);
  123. if(x&&y&&z&&b!=4&&h[i])update(dp[a][b+1][c][x-1][y-1][z-1],o);
  124. if(i<=2)update(DP[a][b][c][cnt[i+1]][x][y],o);
  125. else
  126. {
  127. ll k=cnt[i-2]-z;
  128. o*=C[cnt[i-2]][k]*(flag[i-2]?ksm(2,k):1);
  129. update(DP[a][b][c][cnt[i+1]][x][y],o);
  130. }
  131. }
  132. }
  133. ll ans=0;
  134. for(ll a=0;a<=1;a++)for(ll b=0;b<=4;b++)for(ll c=0;c<=3;c++)if(chk[a][b][c])
  135. for(ll x=0;x<=cnt[tot-0];x++)for(ll y=0;y<=cnt[tot-1];y++)for(ll z=0;z<=cnt[tot-2];z++)
  136. {
  137. ll ka=cnt[tot-0]-x,kb=cnt[tot-1]-y,kc=cnt[tot-2]-z;
  138. dp[a][b][c][x][y][z]*=C[cnt[tot-0]][ka]*(flag[tot-0]?ksm(2,ka):1);
  139. dp[a][b][c][x][y][z]*=C[cnt[tot-1]][kb]*(flag[tot-1]?ksm(2,kb):1);
  140. dp[a][b][c][x][y][z]*=C[cnt[tot-2]][kc]*(flag[tot-2]?ksm(2,kc):1);
  141. if(a==1&&b==4&&c==0)ans=max(ans,dp[a][b][c][x][y][z]);
  142. if(a==1&&b==3&&c==1)ans=max(ans,dp[a][b][c][x][y][z]);
  143. if(a==1&&b==1&&c==3)ans=max(ans,dp[a][b][c][x][y][z]);
  144. if(a==1&&b==4&&c==0)ans=max(ans,dp[a][b][c][x][y][z]);
  145. }
  146. return ans;
  147. }
  148. ll work4()//特殊处理4杠子+1对子
  149. {
  150. ll ans=-inf;
  151. for(ll i=2;i<=4;i++)if(a[i])
  152. {
  153. a[i]--;
  154. ll k,v=4*C[i][2],now=0;
  155. k=min(a[4],4-now);now+=k;v*=ksm(16,k);
  156. k=min(b[4],4-now);now+=k;v*=ksm(1,k);
  157. if(now==4)ans=max(ans,v);
  158. a[i]++;
  159. }
  160. for(ll i=2;i<=4;i++)if(b[i])
  161. {
  162. b[i]--;
  163. ll k,v=1*C[i][2],now=0;
  164. k=min(a[4],4-now);now+=k;v*=ksm(16,k);
  165. k=min(b[4],4-now);now+=k;v*=ksm(1,k);
  166. if(now==4)ans=max(ans,v);
  167. b[i]++;
  168. }
  169. return ans;
  170. }
  171. void solve()
  172. {
  173. clear();
  174. while(true)
  175. {
  176. string s;cin>>s;
  177. if(s[0]=='0')break;
  178. cnt[mp[s]]--;
  179. }
  180. while(true)
  181. {
  182. string s;cin>>s;
  183. if(s[0]=='0')break;
  184. flag[mp[s]]=true;
  185. }
  186. for(ll i=1;i<=tot;i++)if(flag[i])a[cnt[i]]++;else b[cnt[i]]++;
  187. ans=max(ans,work1());ans=max(ans,work2());ans=max(ans,work3());ans=max(ans,work4());
  188. printf("%lld\n",ans);
  189. }
  190. int main()
  191. {
  192. prepare();
  193. ll t=read();
  194. for(ll i=1;i<=t;i++)solve();
  195. return 0;
  196. }

[GXOI/GZOI2019]宝牌一大堆的更多相关文章

  1. [LOJ3084][GXOI/GZOI2019]宝牌一大堆——DP

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

  2. P5301 [GXOI/GZOI2019]宝牌一大堆

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

  3. 【BZOJ5503】[GXOI/GZOI2019]宝牌一大堆(动态规划)

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

  4. [GXOI/GZOI2019]宝牌一大堆(dp)

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

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

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

  6. luogu P5301 [GXOI/GZOI2019]宝牌一大堆

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

  7. [luogu 5301][bzoj 5503] [GXOI/GZOI2019] 宝牌一大堆

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

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

    原题传送门 首先先要学会麻将,然后会发现就是一个暴力dp,分三种情况考虑: 1.非七对子国士无双,设\(dp_{i,j,k,a,b}\)表示看到了第\(i\)种牌,一共有\(j\)个\(i-1\)开头 ...

  9. [GX/GZOI2019]宝牌一大堆(DP)

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

随机推荐

  1. 551.学生出勤记录I

    /* * @lc app=leetcode.cn id=551 lang=java * * [551] 学生出勤记录 I * * https://leetcode-cn.com/problems/st ...

  2. python实现使用词云展示图片

    记录瞬间 首先,要安装一些第三方包 pip install scipyCollecting scipy Downloading https://files.pythonhosted.org/packa ...

  3. github爬虫100项目

    为了更好的巩固所学,在github上开始100爬虫项目,记录学习过程,也希望对他人的学习有帮助,目前还在持续更新中,有兴趣可以看看 地址: https://github.com/mapyJJJ/100 ...

  4. Vue 服务端渲染(SSR)

    什么是服务端渲染? 简单理解是将组件或页面通过服务器生成html字符串,再发送到浏览器,最后将静态标记"混合"为客户端上完全交互的应用程序. 服务端渲染的优点 更好的SEO,搜索引 ...

  5. 用Nuget部署程序包

    用Nuget部署程序包 Nuget是.NET程序包管理工具(类似linux下的npm等),程序员可直接用简单的命令行(或VS)下载包.好处: (1)避免类库版本不一致带来的问题.GitHub是管理源代 ...

  6. 命令行创建cocos2d-x的工程

    1. 命令行创建cocos lua工程cocos new MyGame -p com.your_company.mygame -l lua2. 进入工程目录, 编译运行时库cocos compile ...

  7. PAT (Basic Level) Practice (中文)1006 换个格式输出整数 (15 分)

    题目链接:https://pintia.cn/problem-sets/994805260223102976/problems/994805318855278592 #include <iost ...

  8. 简易轮播图、内含定时器。熟练JS操作

    HTML部分: <!DOCTYPE html><html lang="en"><head> <meta charset="UTF ...

  9. Leetcode 树(102, 637)

    637: 二叉树的层平均值 给定一个非空二叉树,返回一个由每层节点平均值组成的数组: https://leetcode-cn.com/problems/average-of-levels-in-bin ...

  10. opencv学习之路(39)、PCA

    一.PCA理论介绍 网上已经有许多介绍pca原理的博客,这里就不重复介绍了.详情可参考 http://blog.csdn.net/zhongkelee/article/details/44064401 ...