• 【题解】Luogu P5301 [GXOI/GZOI2019]宝牌一大堆


    原题传送门

    首先先要学会麻将,然后会发现就是一个暴力dp,分三种情况考虑:

    1.非七对子国士无双,设(dp_{i,j,k,a,b})表示看到了第(i)种牌,一共有(j)(i-1)开头的顺子,有(k)(i)开头的顺子,有(a)个面子/杠子,有(b)个雀头时最大分数,暴力转移即可

    2.七对子,设(dp_{i,j})表示看到了第(i)种牌,一共有(j)个雀头时最大分数,暴力转移即可

    3.国士无双,设(dp_{i,j})表示看到了国士无双限定的第(i)张牌,已经选了(j)张牌时最大分数,暴力转移即可

    最后比个最大就星了

    #include <bits/stdc++.h>
    #define ll long long
    using namespace std;
    inline void write(register ll x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    int T,v,cnt[35],mrk[35];
    ll 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 bin[5]={1,2,4,8,16};
    inline void upd(register ll &x,register ll y)
    {
        x=x>y?x:y;
    }
    inline ll chose(register int x,register int y)
    {
        return C[cnt[x]][y]*(mrk[x]?bin[y]:1);
    }
    inline ll work1()
    {
        static ll dp[35][3][3][5][2];
        memset(dp,0,sizeof(dp));
        dp[0][0][0][0][0]=1;
        for(register int i=0;i<34;++i)
            for(register int j=0;j<3;++j)
                if(!j||i>7&&(i-7)%9!=0&&(i-7)%9!=1)
                    for(register int k=0;k<3;++k)
                        if(!k||i>7&&(i-7)%9!=8&&(i-7)%9!=0)
                            if(cnt[i+1]>=j+k)
                                for(register int a=j+k;a<=4;++a)
                                    for(register int b=0;b<=1;++b)
                                        if(dp[i][j][k][a][b])
                                        {
                                            for(register int c=0;c<=2&&j+k+c<=cnt[i+1]&&a+c<=4;++c)
                                                for(register int d=0;j+k+c+d*3<=cnt[i+1]&&a+c+d<=4;++d)
                                                {
                                                    int t=j+k+c+d*3;
                                                    upd(dp[i+1][k][c][a+c+d][b],dp[i][j][k][a][b]*chose(i+1,t));
                                                    if(!b&&t+2<=cnt[i+1])
                                                        upd(dp[i+1][k][c][a+c+d][1],dp[i][j][k][a][b]*chose(i+1,t+2));
                                                }
                                            if(cnt[i+1]-j-k==4&&a<4)
                                                upd(dp[i+1][k][0][a+1][b],dp[i][j][k][a][b]*chose(i+1,4));
                                        }
        return dp[34][0][0][4][1];
    }
    inline ll work2()
    {
        static ll dp[35][8];
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(register int i=0;i<34;++i)
            for(register int j=0;j<=7;++j)
            {
                upd(dp[i+1][j],dp[i][j]);
                if(j<7)
                    upd(dp[i+1][j+1],dp[i][j]*chose(i+1,2));
            }
        return dp[34][7]*7;
    }
    int id[]={0,1,2,3,4,5,6,7,8,16,17,25,26,34};
    inline ll work3()
    {
        static ll dp[14][15];
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(register int i=0;i<13;++i)
            for(register int j=0;j<=14;++j)
                for(register int k=1;k<=cnt[id[i+1]]&&k<=2;++k)
                    upd(dp[i+1][j+k],dp[i][j]*chose(id[i+1],k));
        return dp[13][14]*13;
    }
    inline int read()
    {
        int v;
        char str[5];
        scanf("%s",str);
        if(str[0]=='0')
            return 0;
        if(strlen(str)==1)
        {
            if(str[0]=='E')
                v=1;
            else if(str[0]=='S')
                v=2;
            else if(str[0]=='W')
                v=3;
            else if(str[0]=='N')
                v=4;
            else if(str[0]=='Z')
                v=5;
            else if(str[0]=='B')
                v=6;
            else
                v=7;
        }
        else
        {
            if(str[1]=='m')
                v=7;
            else if(str[1]=='p')
                v=16;
            else
                v=25;
            v+=str[0]-'0';
        }
        return v;
    }
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            for(register int i=1;i<=34;++i)
                cnt[i]=4,mrk[i]=0;
            while(v=read())
                --cnt[v];
            while(v=read())
                mrk[v]=1;
            write(max(work1(),max(work2(),work3()))),puts("");
        }
    	return 0;
    }
    
  • 相关阅读:
    java程序打包成jar 配置文件信息路径
    django 认证系统
    django 表单验证和字段验证
    python 面向对象编程
    Python new() 方法
    Django 分页 以及自定义分页
    django 自己编写admin
    Django CRM客户关系管理系统
    Django model中的 class Meta 详解
    Django CRM系统
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/11306732.html
Copyright © 2020-2023  润新知