P5301 [GXOI/GZOI2019]宝牌一大堆
题目
不简化了,太长了
思路
做的第一道NOI/NOI+/CTSC的\(DP\),做这个题要时刻记得各种牌是怎么组成的,\(qwq\)
雀魂大毒瘤,麻将已无爱
- 七对子
直接贪心选择权值最高的七个即可
- 国士无双
暴力枚举,\(O(13^2)\)
- \(3*4+2\)
设\(f[i][j][k][a][b][c]\)表示枚举到第\(i\)张牌,已经有了\(j\)张面子,有有\(k\)对雀头也可,第\(i\)种牌用了\(a\)张,第\(i+1\)种用了\(b\)张,第\(i+3\)种用了\(c\)张的最大分数,或者\(k=0/1\)
然后枚举转移即可
- 性质\(1\)
经过艰难的读题后可以发现杠子是不需要考虑的,因为杠子的价值\(C_4^{4}=1\)就算是宝牌也没有刻子的高\(C_4^{3}=4\)
- 性质\(2\)
三个刻顺子是没有三个刻子更优的,所有对于\(l,m\)只需要枚举到\(2\)就行了
- 性质\(3\)
\(f\)值是\(0\)的话说明不合法直接退出即可
- 转移方程
\(f[i][j][1][k+2][l][m]=max(f[i][j][1][k+2][l][m],\frac{f[i][j][0][k][l][m]}{C_{a[i]}^k}*C_{a[i]}^{k+2}*dora[i]^2)\)
\(f[i][j+1][o][k+3][l][m]=max(f[i][j+1][o][k+3][l][m],\frac{f[i][j][o][k][l][m]}{C_{a[i]}^k}*C_{a[i]}^{k+3}*dora[i]^3)\)
\(f[i][j+1][o][k+1][l+1][m+1]=\max(f[i][j+1][o][k+1][l+1][m+1],\frac{f[i][j][o][k][l][m]}{c_{a[i]}^k}*c_{a[i]}^{k+1}*\frac{dora[i]}{c_{a[i+1]}^l}*c_{a[i+1]}^{l+1}*\frac{dora[i+1]}{c_{a[i+2]}^m}*c_{a[i+2]}^{m+1}*dora[i+2])\)
- 注意
注意在转移之前判断合法不合法(剩的牌够不够),开long long
为什么要开\(O2\)才能过?我吧我忘记判断不合法状态了,\(qwq\)
复杂度为\(O(34*4*4*2*2)=O(2176)\),期望得分:\(100\)
code
/*
@ author:pyyyyyy/guhl37
-----思路------
-----debug-------
*/
#include<queue>
#include<algorithm>
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=55;
char si[5];
int a[N],dora[N],ans,dg[N];
int f[N][5][2][5][3][3];
int c[5][5]= {
1,0,0,0,0,
1,1,0,0,0,
1,2,1,0,0,
1,3,3,1,0,
1,4,6,4,1
};
int yaoku[15]= {0,1,9,10,18,19,27,28,29,30,31,32,33,34};
bool isyaoku[35]= {0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1};
bool tail[35]= {0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1};
int T;
void read() {
while(1) {
/*统计没出手的牌数*/
scanf("%s",si);
if(si[0]=='0') break;
else if(si[1]=='p') a[si[0]-'0']--;
else if(si[1]=='s') a[si[0]-'0'+9]--;
else if(si[1]=='m') a[si[0]-'0'+18]--;
else if(si[0]=='E') a[28]--;
else if(si[0]=='S') a[29]--;
else if(si[0]=='W') a[30]--;
else if(si[0]=='N') a[31]--;
else if(si[0]=='B') a[32]--;
else if(si[0]=='F') a[33]--;
else if(si[0]=='Z') a[34]--;
}
while(1) {
/*统计宝牌*/
scanf("%s",si);
if(si[0]=='0') break;
else if(si[1]=='p') dora[si[0]-'0']=2;
else if(si[1]=='s') dora[si[0]-'0'+9]=2;
else if(si[1]=='m') dora[si[0]-'0'+18]=2;
else if(si[0]=='E') dora[28]=2;
else if(si[0]=='S') dora[29]=2;
else if(si[0]=='W') dora[30]=2;
else if(si[0]=='N') dora[31]=2;
else if(si[0]=='B') dora[32]=2;
else if(si[0]=='F') dora[33]=2;
else if(si[0]=='Z') dora[34]=2;
}
}
void solve1() {
for(int i=1; i<=13; ++i) {
int x=yaoku[i],tmp=13;
tmp*=c[a[x]][2]*dora[x]*dora[x];
for(int j=1; j<=13; ++j) {
if(i==j) continue;
x=yaoku[j];
tmp*=a[x]*dora[x];
}
ans=max(ans,tmp);
}
}
void solve2() {
priority_queue<int> q;
int tmp=7;
for(int i=1; i<=34; ++i) q.push(c[a[i]][2]*dora[i]*dora[i]);
int now;
for(int i=1; i<=7; ++i) {
now=q.top();
q.pop();
tmp*=now;
}
ans=max(ans,tmp);
while(!q.empty()) q.pop();
}
void solve3() {
for(int i=1; i<=34; ++i) {
for(int j=0; j<=4; ++j) {
for(int k=0; k<=4; ++k) {
for(int l=0; l<=2; ++l) {
for(int m=0; m<=2; ++m) {
if(!f[i][j][0][k][l][m]&&!f[i][j][1][k][l][m]) continue;
if(a[i]-k>=2) f[i][j][1][k+2][l][m]=max(f[i][j][1][k+2][l][m],f[i][j][0][k][l][m]/c[a[i]][k]*c[a[i]][k+2]*dora[i]*dora[i]);
if(j<4) {
if(a[i]-k>=3)
for(int o=0; o<=1; ++o)
f[i][j+1][o][k+3][l][m]=max(f[i][j+1][o][k+3][l][m],f[i][j][o][k][l][m]/c[a[i]][k]*c[a[i]][k+3]*dora[i]*dora[i]*dora[i]);
if((!tail[i])&&a[i]-k>0&&a[i+1]-l>0&&a[i+2]-m>0&&l!=2&&m!=2)
for(int o=0; o<=1; ++o) f[i][j+1][o][k+1][l+1][m+1]=max(f[i][j+1][o][k+1][l+1][m+1],f[i][j][o][k][l][m]/c[a[i]][k]*c[a[i]][k+1]*dora[i]/c[a[i+1]][l]*c[a[i+1]][l+1]*dora[i+1]/c[a[i+2]][m]*c[a[i+2]][m+1]*dora[i+2]);
}
f[i+1][j][0][l][m][0]=max(f[i+1][j][0][l][m][0],f[i][j][0][k][l][m]);
f[i+1][j][1][l][m][0]=max(f[i+1][j][1][l][m][0],f[i][j][1][k][l][m]);
if(j==4) dg[i]=max(dg[i],f[i][j][1][k][l][m]);
}
}
}
}
}
for(int i=1; i<=35; ++i) ans=max(ans,dg[i]);
}
signed main() {
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
scanf("%lld",&T);
while(T--) {
memset(dg,0,sizeof(dg));
memset(f,0,sizeof(f));
f[1][0][0][0][0][0]=1;
for(int i=1; i<=34; ++i) a[i]=4,dora[i]=1;
ans=0;
read();
solve1();//国士无双
solve2();//七对子
solve3();//3*4+2
cout<<ans<<'\n';
}
return 0;
}