[GX/GZOI2019]宝牌一大堆(DP)

出这种麻将题有意思吗?

乍看很难实则很水,就是麻将式DP,想必大家很熟悉了吧。首先把“国士无双”和“七对子”两种牌型判掉,然后观察牌胡的形式,发现每多一张牌实际上就是把1个面子变成1个杠子,然后可以直接DP啦!f[i][j][k][p][q]表示到第i种牌型,(i-2,i-1,i)有j个,(i-1,i,i+1)有k个,然后面子+杠子共p个,q=0/1表示是否有对子的最大值,暴力转移即可。

不知道为啥,luogu满分,LOJ RE成0分,这种垃圾题,不想管了。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int id[14]={0,1,2,3,4,5,6,7,8,16,17,25,26,34};
int mp[200],cnt[35],vis[35],c[5][5];
ll f[35][3][3][5][2],g[35][15];
ll upd(ll&x,ll y){x=x>y?x:y;}
int read()
{
    char str[5];scanf("%s",str);
    if(str[0]=='0')return 0;
    if(strlen(str)==1)return mp[str[0]];
    if(str[1]=='m')return 7+str[0]-'0';
    if(str[1]=='p')return 16+str[0]-'0';
    return 25+str[0]-'0';
}
ll cal(int x,int y){return(1ll<<(vis[x]?y:0))*c[cnt[x]][y];}
ll gsws()
{
    memset(g,0,sizeof g);
    g[0][0]=1;
    for(int i=0;i<13;i++)
    for(int j=0;j<=14;j++)
    for(int k=1;k<=cnt[id[i+1]]&&k<=2&&j+k<=14;k++)
    upd(g[i+1][j+k],g[i][j]*cal(id[i+1],k));
    return 13*g[13][14];
}
ll qdz()
{
    memset(g,0,sizeof g);
    g[0][0]=1;
    for(int i=0;i<34;i++)
    for(int j=0;j<=7;j++)
    {
        upd(g[i+1][j],g[i][j]);
        if(j<7)upd(g[i+1][j+1],g[i][j]*cal(i+1,2));
    }
    return 7*g[34][7];
}
ll solve()
{
    memset(f,0,sizeof f);
    f[0][0][0][0][0]=1;
    for(int i=0;i<34;i++)
    for(int j=0;j<3;j++)
    if(!j||i>7&&(i-7)%9!=0&&(i-7)%9!=1)
    for(int k=0;k<3;k++)
    if(!k||i>7&&(i-7)%9!=8&&(i-7)%9!=0&&cnt[i+1]>=j+k)
    for(int p=j+k;p<=4;p++)
    for(int q=0;q<=1;q++)
    if(f[i][j][k][p][q])
    {
        for(int a=0;a<=2&&j+k+a<=cnt[i+1]&&p+a<=4;a++)
        for(int b=0;j+k+a+b*3<=cnt[i+1]&&p+a+b<=4;b++)
        {
            upd(f[i+1][k][a][p+a+b][q],f[i][j][k][p][q]*cal(i+1,j+k+a+b*3));
            if(!q&&j+k+a+b*3+2<=cnt[i+1])
            upd(f[i+1][k][a][p+a+b][1],f[i][j][k][p][q]*cal(i+1,j+k+a+b*3+2));
        }
        if(cnt[i+1]-j-k==4&&p<4)upd(f[i+1][k][0][p+1][q],f[i][j][k][p][q]*cal(i+1,4));
    }
    return f[34][0][0][4][1];
}
int main()
{
    mp['E']=1,mp['S']=2,mp['W']=3,mp['N']=4,mp['Z']=5,mp['B']=6,mp['F']=7;
    for(int i=0;i<=4;i++)
    {
        c[i][0]=1;
        for(int j=1;j<=i;j++)c[i][j]=c[i-1][j]+c[i-1][j-1];
    }
    int T,v;scanf("%d",&T);
    while(T--)
    {
        for(int i=1;i<=34;i++)cnt[i]=4,vis[i]=0;
        while(v=read())cnt[v]--;
        while(v=read())vis[v]=1;
        printf("%lld\n",max(solve(),max(qdz(),gsws())));
    }
}
View Code

 

posted @ 2019-05-12 17:12  hfctf0210  阅读(311)  评论(0编辑  收藏  举报