首先先要学会麻将,然后会发现就是一个暴力dp,分三种情况考虑:
1.非七对子国士无双,设(dp_{i,j,k,a,b})表示看到了第(i)种牌,一共有(j)个(i-1)开头的顺子,有(k)个(i)开头的顺子,有(a)个面子/杠子,有(b)个雀头时最大分数,暴力转移即可
2.七对子,设(dp_{i,j})表示看到了第(i)种牌,一共有(j)个雀头时最大分数,暴力转移即可
3.国士无双,设(dp_{i,j})表示看到了国士无双限定的第(i)张牌,已经选了(j)张牌时最大分数,暴力转移即可
最后比个最大就星了
#include <bits/stdc++.h>
#define ll long long
using namespace std;
inline void write(register ll x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
int T,v,cnt[35],mrk[35];
ll 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}
};
ll bin[5]={1,2,4,8,16};
inline void upd(register ll &x,register ll y)
{
x=x>y?x:y;
}
inline ll chose(register int x,register int y)
{
return C[cnt[x]][y]*(mrk[x]?bin[y]:1);
}
inline ll work1()
{
static ll dp[35][3][3][5][2];
memset(dp,0,sizeof(dp));
dp[0][0][0][0][0]=1;
for(register int i=0;i<34;++i)
for(register int j=0;j<3;++j)
if(!j||i>7&&(i-7)%9!=0&&(i-7)%9!=1)
for(register int k=0;k<3;++k)
if(!k||i>7&&(i-7)%9!=8&&(i-7)%9!=0)
if(cnt[i+1]>=j+k)
for(register int a=j+k;a<=4;++a)
for(register int b=0;b<=1;++b)
if(dp[i][j][k][a][b])
{
for(register int c=0;c<=2&&j+k+c<=cnt[i+1]&&a+c<=4;++c)
for(register int d=0;j+k+c+d*3<=cnt[i+1]&&a+c+d<=4;++d)
{
int t=j+k+c+d*3;
upd(dp[i+1][k][c][a+c+d][b],dp[i][j][k][a][b]*chose(i+1,t));
if(!b&&t+2<=cnt[i+1])
upd(dp[i+1][k][c][a+c+d][1],dp[i][j][k][a][b]*chose(i+1,t+2));
}
if(cnt[i+1]-j-k==4&&a<4)
upd(dp[i+1][k][0][a+1][b],dp[i][j][k][a][b]*chose(i+1,4));
}
return dp[34][0][0][4][1];
}
inline ll work2()
{
static ll dp[35][8];
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(register int i=0;i<34;++i)
for(register int j=0;j<=7;++j)
{
upd(dp[i+1][j],dp[i][j]);
if(j<7)
upd(dp[i+1][j+1],dp[i][j]*chose(i+1,2));
}
return dp[34][7]*7;
}
int id[]={0,1,2,3,4,5,6,7,8,16,17,25,26,34};
inline ll work3()
{
static ll dp[14][15];
memset(dp,0,sizeof(dp));
dp[0][0]=1;
for(register int i=0;i<13;++i)
for(register int j=0;j<=14;++j)
for(register int k=1;k<=cnt[id[i+1]]&&k<=2;++k)
upd(dp[i+1][j+k],dp[i][j]*chose(id[i+1],k));
return dp[13][14]*13;
}
inline int read()
{
int v;
char str[5];
scanf("%s",str);
if(str[0]=='0')
return 0;
if(strlen(str)==1)
{
if(str[0]=='E')
v=1;
else if(str[0]=='S')
v=2;
else if(str[0]=='W')
v=3;
else if(str[0]=='N')
v=4;
else if(str[0]=='Z')
v=5;
else if(str[0]=='B')
v=6;
else
v=7;
}
else
{
if(str[1]=='m')
v=7;
else if(str[1]=='p')
v=16;
else
v=25;
v+=str[0]-'0';
}
return v;
}
int main()
{
scanf("%d",&T);
while(T--)
{
for(register int i=1;i<=34;++i)
cnt[i]=4,mrk[i]=0;
while(v=read())
--cnt[v];
while(v=read())
mrk[v]=1;
write(max(work1(),max(work2(),work3()))),puts("");
}
return 0;
}