奶了一口CSP考麻将就要去写一下麻将题嘛……
然而因为是CSP所以就挑了个简单点的= =
首先国士无双可以直接\(13^2\)枚举,七对可以贪心
然后因为\(2^4*\binom{4}{4}<2^3*\binom{4}{3}\),所以杠子是没有用的,于是就只用枚举\(3\times4+2\)的情况
设\(dp[pos][j][0/1][i1][i2]\)表示现在在枚举第\(pos\)种牌,有了\(j\)个面子,有无雀头,有\(i1\)个\(pos-1,pos,pos+1\)的顺子,有\(i2\)个\(pos,pos+1,pos+2\)的顺子的情况
然后你发现当\(i1\geq 3\)时,可以直接组成\(3\)个刻子,\(i2\)同理
所以\(i1,i2\)都只用枚举到\(2\)
分类讨论每种牌暴力转移即可,注意数组不要越界
感觉自己代码挺短
#include <bits/stdc++.h>
#define N
#define ll long long
#define For(i,x,y) for(int i=(x);i<=(y);++i)
#define Rof(i,x,y) for(int i=(x);i>=(y);--i)
#define file(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout)
using namespace std;
//1-9:万 10-18:索 19-27:筒 28-32:东西南北中 33:白 34:发
ll dp[40][5][2][3][3],ans=0,qd[40],_2[40],C[40][40];//pos,面子,雀头,pos-1 pos pos+1,pos pos+1 pos+2
char s[5];
int num[40],gsws[14]={0,1,9,10,18,19,27,28,29,30,31,32,33,34};
bool is[40];
void init(){
For(i,1,34) num[i]=4,is[i]=0;
For(i,0,34) For(j,0,4) For(k,0,1) For(p,0,2) For(q,0,2)
dp[i][j][k][p][q]=0;
}
void getcard(){
while(1){
scanf("\n%s",s+1);
int l=strlen(s+1);
if(s[1]=='0') break;
if(l==2){
if(s[2]=='m') num[s[1]-'0']--;
else if(s[2]=='s') num[s[1]-'0'+9]--;
else if(s[2]=='p') num[s[1]-'0'+18]--;
} else{
if(s[1]=='E') num[28]--;
else if(s[1]=='W') num[29]--;
else if(s[1]=='S') num[30]--;
else if(s[1]=='N') num[31]--;
else if(s[1]=='Z') num[32]--;
else if(s[1]=='B') num[33]--;
else if(s[1]=='F') num[34]--;
}
}
while(1){
scanf("\n%s",s+1);
if(s[1]=='0') break;
int l=strlen(s+1);
if(l==2){
if(s[2]=='m') is[s[1]-'0']=1;
else if(s[2]=='s') is[s[1]-'0'+9]=1;
else if(s[2]=='p') is[s[1]-'0'+18]=1;
} else{
if(s[1]=='E') is[28]=1;
else if(s[1]=='W') is[29]=1;
else if(s[1]=='S') is[30]=1;
else if(s[1]=='N') is[31]=1;
else if(s[1]=='Z') is[32]=1;
else if(s[1]=='B') is[33]=1;
else if(s[1]=='F') is[34]=1;
}
}
}
void upd(ll &x,ll y){ x<y?x=y:x=x; }
ll calc(int x,int y){ return (is[x]?_2[y]:1)*C[num[x]][y]; }
ll GSWS(){
ll qwq=0;
For(i,1,13) if(!num[gsws[i]]) return 0;
For(i,1,13){
ll tmp=1;
if(num[gsws[i]]>=2){
For(j,1,13){
if(i==j) tmp*=calc(gsws[j],2);
else tmp*=calc(gsws[j],1);
}
}
qwq=max(qwq,tmp);
}
return qwq*13ll;
}
ll QD(){
ll qwq=1;int ewe=0;
For(i,1,34) if(num[i]>=2) qd[++ewe]=calc(i,2);
if(ewe<7) return 0;
sort(qd+1,qd+ewe+1);
Rof(i,ewe,ewe-6) qwq*=qd[i];
return qwq*7ll;
}
void solve(){
init(),ans=0;
getcard();
ans=max(ans,GSWS());
ans=max(ans,QD());
dp[0][0][0][0][0]=1;
For(pos,0,33) For(j,0,4) For(qt,0,1) For(i1,0,2) For(i2,0,2){
if(!dp[pos][j][qt][i1][i2]) continue;
int lim=0;
if(pos+1<=27 && pos+3<=(pos/9+1)*9) lim=2;
if(!qt){
if(num[pos+1]-i1-i2>=2){
For(k,0,(num[pos+1]-i1-i2-2)/3) For(i3,0,lim){
if(i2+i3>num[pos+2] || i1+i2+i3+k*3+2>num[pos+1] || i3>num[pos+3] || j+i3+k>4) continue;
int tmp=i1+i2+i3+k*3+2;
upd(dp[pos+1][j+i3+k][1][i2][i3],dp[pos][j][qt][i1][i2]*calc(pos+1,tmp));
}
}
}
For(k,0,(num[pos+1]-i1-i2)/3) For(i3,0,lim){
if(i2+i3>num[pos+2] || i1+i2+i3+3*k>num[pos+1] || i3>num[pos+3] || j+i3+k>4) continue;
int tmp=i1+i2+i3+k*3;
upd(dp[pos+1][j+i3+k][qt][i2][i3],dp[pos][j][qt][i1][i2]*calc(pos+1,tmp));
}
}
ans=max(ans,dp[34][4][1][0][0]);
printf("%lld\n",ans);
}
int main(){
C[0][0]=_2[0]=1;
For(i,1,34) C[i][0]=1;
For(i,1,34) For(j,1,i) C[i][j]=C[i-1][j]+C[i-1][j-1];
For(i,1,34) _2[i]=2ll*_2[i-1];
int T;scanf("%d",&T);
while(T--) solve();
}