【麻将+DP】洛谷P5301

奶了一口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();
}

猜你喜欢

转载自www.cnblogs.com/PsychicBoom/p/11861035.html
今日推荐