Description
Link.
Summarizing the fucking statement is the last thing in the world I ever want to do.
Solution
我们来重新描述一些概念:
- 数字牌:筒条万。
- 顺子:(3) 张连续的数字牌。(面子)
- 雀头:(2) 张完全一样的牌。
- 刻子:(3) 张完全一样的牌。(面子)
- 杠子:(4) 张完全一样的牌。
观察发现:杠子在除了 (14) 张牌胡牌情况以外的胡牌情况都出现了,于是又发现:(inom{4}{3}>inom{4}{4});
于是:
- 对于胡牌的形式,我们只需要考虑「(3 imes4+2)」「七对子」和「国士无双」。
于是我们只需要三种情况取最大即可。
-
「七对子」只需要把所有牌型的贡献拉出来,取前 (7) 个最大的乘起来即可。
-
「国士无双」枚举谁来做 (2) 个的那个,然后取最大。
-
「(3 imes4+2)」
(qquad) 考虑这样一个 DP,设:(f(i,j,k,a,b,c)) 为前 (i) 个数,(j) 个面子,(k) 个雀头,第 (i) / (i+1) / (i+2) 张牌用了 (a) / (b) / (c) 张的最优答案((kin{0,1}))。
(qquad) (qquad) 1. 对于雀头:
[f(i,j,1,a+2,b,c)=max{frac{f(i,j,0,a,b,c) imes ext{calc}(i,a+2)}{ ext{calc}(i,a)}}
]
(qquad) (qquad) (qquad) 其中 ( ext{calc}(x,y)) 为第 (x) 张牌,在手牌中需要出现 (y) 次,此时对答案的贡献。
(qquad) (qquad) (qquad) 方程的意义即:去掉把第 (i) 种牌之前的贡献,再算上现在算作雀头的贡献。
(qquad) (qquad) 2. 对于刻子:
[f(i,j+1,0 ext{ or }1,a+3,b,c)=max{frac{f(i,j,0 ext{ or }1,a,b,c) imes ext{calc}(i,a+3)}{ ext{calc}(i,a)}}
]
(qquad) (qquad) (qquad) 基本同上。
(qquad) (qquad) 3. 对于顺子:
[f(i,j+1,0 ext{ or }1,a+1,b+1,c+1)=max{frac{f(i,j,0 ext{ or }1,a,b,c) imes ext{calc}(i,a+1) imes ext{calc}(i+1,b+1) imes ext{calc}(i+2,c+1)}{ ext{calc}(i,a) imes ext{calc}(i+1,b) imes ext{calc}(i+2,c)}}
]
(qquad) (qquad) (qquad) 完全同理。
然后就完了。
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL koshi[15]={0,1,9,10,18,19,27,28,29,30,31,32,33,34}; // the cards that Kokushimusou needs
const bool chunko[36]={0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1}; // the cards which are able to be jyunko
LL getCard()
{
static char s[10];
scanf("%s",s+1);
if(s[1]=='0') return -1;
else if(!isdigit(s[1]))
{
if(s[1]=='E') return 28;
else if(s[1]=='S') return 29;
else if(s[1]=='W') return 30;
else if(s[1]=='N') return 31;
else if(s[1]=='Z') return 32;
else if(s[1]=='B') return 33;
else return 34;
}
else
{
if(s[2]=='m') return s[1]-'0';
else if(s[2]=='p') return s[1]-'0'+9;
else return s[1]-'0'+18;
}
}
LL t,comb[10][10],cnt[40],trs[40],f[40][5][5][5][5][5];
#define calc(x,f) (((cnt[x])<(f)?0:comb[cnt[x]][f])*(trs[x]?(1<<(f)):1))
LL onesolve() // Seven Pairs
{
vector<LL> pri;
for(LL i=1;i<=34;++i) if(cnt[i]>=2) pri.push_back(calc(i,2));
sort(pri.begin(),pri.end(),greater<LL>());
if(pri.size()<size_t(7)) return 0;
else
{
LL res=7;
for(LL i=0;i<7;++i) res*=pri[i];
return res;
}
}
LL anosolve() // Kokushimusou
{
LL flag=0;
for(LL i=1;i<=13;++i)
{
if(cnt[koshi[i]]>=2) flag=1;
if(cnt[koshi[i]]==0) return 0;
}
if(flag)
{
LL res=0;
for(LL i=1;i<=13;++i)
{
LL tmp=13;
if(cnt[koshi[i]]>=2)
{
for(LL j=1;j<=13;++j) tmp*=calc(koshi[j],(i==j)+1);
}
res=max(res,tmp);
}
return res;
}
else return 0;
}
void getmax(LL &one,LL ano){one=max(one,ano);}
LL exsolve() // 3x4+2
{
#define f(i,j,k,a,b,c) (f[i][j][k][a][b][c])
f(1,0,0,0,0,0)=1;
for(LL i=1;i<=34;++i)
{
for(LL j=0;j<=4;++j)
{
for(LL a=0;a<=4;++a)
{
for(LL b=0;b<=2;++b)
{
for(LL c=0;c<=2;++c)
{
if(cnt[i]-a>=2) getmax(f(i,j,1,a+2,b,c),f(i,j,0,a,b,c)/calc(i,a)*calc(i,a+2));
if(j^4)
{
if(cnt[i]-a>=3)
{
getmax(f(i,j+1,0,a+3,b,c),f(i,j,0,a,b,c)/calc(i,a)*calc(i,a+3));
getmax(f(i,j+1,1,a+3,b,c),f(i,j,1,a,b,c)/calc(i,a)*calc(i,a+3));
}
if(chunko[i]&&cnt[i]-a>=1&&cnt[i+1]-b>=1&&cnt[i+2]-c>=1&&(b^2)&&(c^2))
{
getmax(f(i,j+1,0,a+1,b+1,c+1),f(i,j,0,a,b,c)/calc(i,a)/calc(i+1,b)/calc(i+2,c)*calc(i,a+1)*calc(i+1,b+1)*calc(i+2,c+1));
getmax(f(i,j+1,1,a+1,b+1,c+1),f(i,j,1,a,b,c)/calc(i,a)/calc(i+1,b)/calc(i+2,c)*calc(i,a+1)*calc(i+1,b+1)*calc(i+2,c+1));
}
}
getmax(f(i+1,j,0,b,c,0),f(i,j,0,a,b,c));
getmax(f(i+1,j,1,b,c,0),f(i,j,1,a,b,c));
}
}
}
}
}
LL res=0;
for(LL i=1;i<=34;++i)
{
for(LL a=0;a<=4;++a)
{
for(LL b=0;b<=2;++b)
{
for(LL c=0;c<=2;++c) getmax(res,f(i,4,1,a,b,c));
}
}
}
#undef f
return res;
}
int main()
{
for(LL i=0;i<=4;++i) comb[i][0]=comb[i][i]=1;
for(LL i=1;i<=4;++i) for(LL j=1;j<i;++j) comb[i][j]=comb[i-1][j-1]+comb[i-1][j];
scanf("%lld",&t);
while(t--)
{
memset(f,0,sizeof(f));
for(LL i=1;i<=34;++i) cnt[i]=4,trs[i]=0;
LL tmp=getCard();
while(~tmp) --cnt[tmp],tmp=getCard();
tmp=getCard();
while(~tmp) trs[tmp]=1,tmp=getCard();
printf("%lld
",max(max(onesolve(),anosolve()),exsolve()));
}
return 0;
}