zoukankan      html  css  js  c++  java
  • [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
    ",max(solve(),max(qdz(),gsws())));
        }
    }
    View Code
  • 相关阅读:
    计算两个字符串的最大公共字串的长度,字符不区分大小写
    任何一个整数m的立方都可以写成m个连续奇数之和。
    求一个byte数字对应的二进制数字中1的最大连续数
    Elasticsearch的过滤查询
    如何在Elasticsearch中安装中文分词器(IK+pinyin)
    使用Linux的alternatives命令替换选择软件的版本
    PHP如何与搜索引擎Elasticsearch交互?
    如何安装搜索引擎Elasticsearch?
    如何修改MAC自带的PHP的版本?
    程序员技能图谱
  • 原文地址:https://www.cnblogs.com/hfctf0210/p/10852871.html
Copyright © 2011-2022 走看看