首先,杠子是一定不比面子优的,即便杠子是宝牌,也没有合成一个面子的分值高,这意味着我们只需要考虑「$3 \times 4 + 2$」、「七对子」、「国士无双」三种和牌方式了,很显然「七对子」和「国士无双」都可以直接算出,「七对子」用优先队列直接处理,「国士无双」也可以用 $O(13^2)$ 的时间暴力算出,只剩下了一个「$3 \times 4 + 2$」不是很好算,考虑 $\rm{DP}$ 计算出最优的「$3 \times 4 + 2$」.

设 $f_{i,j,k,a,b,c}$ 表示枚举了前 $i$ 种牌,凑齐了 $j$ 对面子,$k$ 对雀头,第 $i,i+1,i+2$ 种牌的已用数量分别为 $a,b,c$ 时的最大收益

转移时考虑面子和雀头 (如 $i$ 为宝牌,则 $dora_i$ 等于 $2$ ,否则等于 $1$) :

  • 雀头转移:

    $$f_{i,j,k+1,a+2,b,c}=f_{i,j,k,a,b,c}\times \frac{C_{a_i}^{k+2}}{C_{a_i}^{k}}\times dora_i^2$$

  • 刻子转移:

    $$f_{i,j+1,k,a+3,b,c}=f_{i,j,k,a,b,c}\times \frac{C_{a_i}^{k+3}}{C_{a_i}^{k}}\times dora_i^3$$

  • 顺子转移:

    $$f_{i,j+1,k,a+1,b+1,c+1}=f_{i,j,k,a,b,c}\times \frac{C_{s_i}^{a+1}}{C_{s_i}^{a}}\times \frac{C_{s_{i+1}}^{b+1}}{C_{s_{i+1}}^{b}}\times \frac{C_{s_{i+2}}^{c+1}}{C_{s_{i+2}}^{c}}\times dora_i\times dora_{i+1}\times dora_{i+2}$$

注意细节 $qwq$ .

Code:

#include <queue>
#include <cstdio>
#include <string>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;

int T,s[40],d[40],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 ans,num[40],dp[40][6][2][6][6][6];
bool book[40]={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 special[15]={0,1,9,10,18,19,27,28,29,30,31,32,33,34};
char str[15];

int id() {
    if(str[0]=='E') return 28;
    else if(str[0]=='S') return 29;
    else if(str[0]=='W') return 30;
    else if(str[0]=='N') return 31;
    else if(str[0]=='Z') return 32;
    else if(str[0]=='B') return 33;
    else if(str[0]=='F') return 34;
    else if(str[1]=='m') return str[0]-'0';
    else if(str[1]=='p') return 9+str[0]-'0';
    else if(str[1]=='s') return 18+str[0]-'0';
}

priority_queue<int> q;
void Special_1() {
    while(!q.empty()) q.pop();
    ll res=7;
    for(int i=1;i<=34;++i)
        if(s[i]>=2) q.push(C[s[i]][2]*d[i]*d[i]);
    if(q.size()<7) return;
    for(int i=1;i<=7;++i)
        res=1ll*res*q.top(),q.pop();
    ans=max(ans,res);
}
void Special_2() {
    for(int i=1;i<=13;++i) if(!s[special[i]]) return;
    for(int i=1;i<=13;++i) {
        int x=special[i];
        if(s[x]<2) continue;
        ll res=13ll*C[s[x]][2]*d[x]*d[x];
        for(int j=1;j<=13;++j) {
            if(i==j) continue;
            int y=special[j];
            res=1ll*res*C[s[y]][1]*d[y];
        }
        ans=max(ans,res);
    }
}

void chkmax(ll&x,ll y) {x=max(x,y);}
void work(int i,int j,int a,int b,int c) {
    if(s[i]-a>=2) chkmax(dp[i][j][1][a+2][b][c],1ll*dp[i][j][0][a][b][c]/C[s[i]
    ][a]*C[s[i]][a+2]*d[i]*d[i]);
    if(j<4) {
        if(s[i]-a>=3) for(int k=0;k<=1;++k)
            chkmax(dp[i][j+1][k][a+3][b][c],1ll*dp[i][j][k][a][b][c]/C[s[i]][a]
            *C[s[i]][a+3]*d[i]*d[i]*d[i]);
        if(!book[i]&&s[i]-a>0&&s[i+1]-b>0&&s[i+2]-c>0) for(int k=0;k<=1;++k) 
            chkmax(dp[i][j+1][k][a+1][b+1][c+1],1ll*dp[i][j][k][a][b][c]/C[s[i]
            ][a]*C[s[i]][a+1]/C[s[i+1]][b]*C[s[i+1]][b+1]/C[s[i+2]][c]*C[s[i+2]
            ][c+1]*d[i]*d[i+1]*d[i+2]);
    }
}

void solve() {
    while(true) {scanf("%s",str);if(str[0]=='0') break;--s[id()];}
    while(true) {scanf("%s",str);if(str[0]=='0') break;d[id()]=2;}
    Special_1();
    Special_2();
    for(int i=1;i<=34;++i)
        for(int j=0;j<=4;++j)
            for(int a=0;a<=s[i];++a)
                for(int b=0;b<=s[i+1];++b)
                    for(int c=0;c<=s[i+2];++c) {
                        if(!dp[i][j][0][a][b][c]&&!dp[i][j][1][a][b][c]) continue;
                        work(i,j,a,b,c);
                        chkmax(dp[i+1][j][0][b][c][0],dp[i][j][0][a][b][c]);
                        chkmax(dp[i+1][j][1][b][c][0],dp[i][j][1][a][b][c]);
                        if(j==4) num[i]=max(num[i],dp[i][j][1][a][b][c]);
                    }
    for(int i=1;i<=35;++i) ans=max(ans,num[i]);
    printf("%lld\n",ans);
}

void clear() {
    memset(dp,0,sizeof(dp)),ans=0;
    memset(num,0,sizeof(num));
    for(int i=1;i<=34;++i) s[i]=4,d[i]=1;
    dp[1][0][0][0][0][0]=1;
}

int main() {
    scanf("%d",&T);
    while(T--) clear(),solve();
    return 0;
}
分类: 文章

Qiuly

QAQ

0 条评论

发表回复

Avatar placeholder

您的电子邮箱地址不会被公开。 必填项已用*标注