In mathematics you don't understand things, you just get used to them.

Description

Link.

Summarizing the fucking statement is the last thing in the world I ever want to do.

Solution

我们来重新描述一些概念:

  • 数字牌:筒条万。
  • 顺子:$3$ 张连续的数字牌。(面子)
  • 雀头:$2$ 张完全一样的牌。
  • 刻子:$3$ 张完全一样的牌。(面子)
  • 杠子:$4$ 张完全一样的牌。

观察发现:杠子在除了 $14$ 张牌胡牌情况以外的胡牌情况都出现了,于是又发现:$\binom{4}{3}>\binom{4}{4}$;

于是:

  • 对于胡牌的形式,我们只需要考虑「$3\times4+2$」「七对子」和「国士无双」。

于是我们只需要三种情况取最大即可。

  1. 「七对子」只需要把所有牌型的贡献拉出来,取前 $7$ 个最大的乘起来即可。
  2. 「国士无双」枚举谁来做 $2$ 个的那个,然后取最大。
  3. 「$3\times4+2$」

$\qquad$ 考虑这样一个 DP,设:$f(i,j,k,a,b,c)$ 为前 $i$ 个数,$j$ 个面子,$k$ 个雀头,第 $i$ / $i+1$ / $i+2$ 张牌用了 $a$ / $b$ / $c$ 张的最优答案($k\in\{0,1\}$)。

$\qquad$ $\qquad$ 1. 对于雀头:

$$ f(i,j,1,a+2,b,c)=\max\{\frac{f(i,j,0,a,b,c)\times\text{calc}(i,a+2)}{\text{calc}(i,a)}\} $$

$\qquad$ $\qquad$ $\qquad$ 其中 $\text{calc}(x,y)$ 为第 $x$ 张牌,在手牌中需要出现 $y$ 次,此时对答案的贡献。

$\qquad$ $\qquad$ $\qquad$ 方程的意义即:去掉把第 $i$ 种牌之前的贡献,再算上现在算作雀头的贡献。

$\qquad$ $\qquad$ 2. 对于刻子:

$$ f(i,j+1,0\text{ or }1,a+3,b,c)=\max\{\frac{f(i,j,0\text{ or }1,a,b,c)\times\text{calc}(i,a+3)}{\text{calc}(i,a)}\} $$

$\qquad$ $\qquad$ $\qquad$ 基本同上。

$\qquad$ $\qquad$ 3. 对于顺子:

$$ f(i,j+1,0\text{ or }1,a+1,b+1,c+1)=\max\{\frac{f(i,j,0\text{ or }1,a,b,c)\times\text{calc}(i,a+1)\times\text{calc}(i+1,b+1)\times\text{calc}(i+2,c+1)}{\text{calc}(i,a)\times\text{calc}(i+1,b)\times\text{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\n",max(max(onesolve(),anosolve()),exsolve()));
    }
    return 0;
}

dp implementation

Solution -「ZJOI 2014」力
上一篇 «
Solution -「CSP 2019」Centroid
» 下一篇