习题:宝牌一大堆(DP&卡常)

题目

传送门

思路

这道题主要是状态不好想和题目不好理解

如果你和笔者一样没有接触过麻将

我们首先将整个麻将进行hash处理

定义\(dp_{i,j,k,l,m,n}\)为前i种牌,杠子和面子总共的数量为j,雀子的数量为k,第\(i-2\)种牌的数量为l,第\(i-1\)种牌的数量为m,第种i牌的数量为n

需要特别注意的是,DP的值是不将i-2~i这三种牌考虑进去的

那么可以写出转移

\(\begin{cases}dp_{i,j+1,k,l+1,m+1,n+1}(\mbox{顺子})\\dp_{i,j+1,k,l,m,n+3}(刻子)\\dp_{i,j+1,k,l,m,n+4}(杠头)\\dp_{i,j,k+1,l,m,n+2}(雀子)\end{cases}\)=\(dp_{i,j,k,l,m,n}\)

直接原地转移,因为我们的\(dp\)中不考虑i-2~i种棋牌的​

还有一种情况

\(dp_{i+1,j,k,m,n,0}=dp_{i,j,k,m,n,l}*C_{t_{i}}^l*qkpow(bp_i,l)\)

其中 \(t_i\)表示i种棋牌剩余的个数,\(bp_i=\begin{cases}2[第i种数是宝牌]\\1[第i种不是宝牌]\end{cases}\)

方程的意义就为不考虑i种棋牌时,当前的\(dp\)状态向后转移,也挺好理解的

最后统计一下,统计的时候别忘了加上最后三种棋牌的贡献

接着说一下优化

当前状态为0可以直接跳过

证明:最后的状态一定是一个乘积式,当其中一项为0,整个就直接为0

可以不用考虑杠子

证明:\(C_4^3=4且C_4^4=1\)也就是说即使这张牌是宝牌不是不划算的

但是这并不代表着循环的条件会变,我们只是多continue几个状态

其实都是常数级的减小

但是可以让你从50分直升100分

这道题真是道好(毒瘤)题

常数的重要性一览无余

代码

#pragma GCC optimize(2)
#include<iostream>
#include<cstring>
#include<climits>
#include<queue>
using namespace std;
int T;
priority_queue<int> q;
long long ans;
long long tmp;
int num_pow[3][5];
long long dp[35][5][2][5][5][5];
int sz[35]={0,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,0,0,0,0,0,0,0};
int gs[14]={0,1,9,10,18,19,27,28,29,30,31,32,33,34};
int t[35];
int bp[35];
int 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}
};
string a;
int solve_hash(string a)
{
    if(a[1]=='m')
        return a[0]-'0';
    if(a[1]=='p')
        return a[0]-'0'+9;
    if(a[1]=='s')
        return a[0]-'0'+18;
    if(a[0]=='E')
        return 28;
    if(a[0]=='S')
        return 29;
    if(a[0]=='W')
        return 30;
    if(a[0]=='N')
        return 31;
    if(a[0]=='Z')
        return 32;
    if(a[0]=='B')
        return 33;
    if(a[0]=='F')
        return 34;
}
void init()
{
    while(!q.empty())
        q.pop();
    memset(dp,0,sizeof(dp));
    dp[1][0][0][0][0][0]=1;
    ans=0;
    for(int i=1;i<=34;i++)
    {
        bp[i]=1;
        t[i]=4;
    }
}
int qkpow(int a,int b)
{
    if(num_pow[a][b])
        return num_pow[a][b];
    if(b==0)
        return 1;
    if(b==1)
        return a;
    long long t=qkpow(a,b/2);
    t=(t*t);
    if(b%2==1)
        t*=a;
    num_pow[a][b]=t;
    return t;
}
void c_in()
{
    init();
    while(1)
    {
        cin>>a;
        if(a[0]=='0')
            break;
        t[solve_hash(a)]--;
    }
    while(1)
    {
        cin>>a;
        if(a[0]=='0')
            break;
        bp[solve_hash(a)]=2;
    }
    for(int i=1;i<=13;i++)
    {
        tmp=1;
        for(int j=1;j<=13;j++)
        {
            if(i==j)
            {
                if(t[gs[i]]<2)
                    tmp=0;
                else
                    tmp=tmp*c[t[gs[i]]][2]*qkpow(bp[gs[i]],2);
            }
            else
            {
                if(!t[gs[j]])
                    tmp=0;
                else
                    tmp=tmp*c[t[gs[j]]][1]*qkpow(bp[gs[j]],1);
            }
        }
        ans=max(ans,tmp*13);
    }
    for(int i=1;i<=34;i++)
        if(t[i]>=2)
            q.push(c[t[i]][2]*qkpow(bp[i],2));
    if(q.size()>=7)
    {
        tmp=1;
        for(int i=1;i<=7;i++)
        {
            tmp=tmp*q.top();
            q.pop();
        }
        ans=max(ans,tmp*7);
    }
    for(int i=1;i<=34;i++)
    {
        for(int j=0;j<=4;j++)
        {
            for(int k=0;k<=1;k++)
            {
                for(int l=0;l<=4;l++)
                {
                    for(int m=0;m<=4;m++)
                    {
                        for(int n=0;n<=4;n++)
                        {
                            long long now=dp[i][j][k][l][m][n];
                            if(!now)
                                continue;   
                            if(k==0&&t[i]-n>=2)
                                dp[i][j][k+1][l][m][n+2]=max(dp[i][j][k+1][l][m][n+2],now);
                            if(t[i]-n>=3&&j<4)
                                dp[i][j+1][k][l][m][n+3]=max(dp[i][j+1][k][l][m][n+3],now);
                            if(sz[i]&&t[i-2]-l>=1&&t[i-1]-m>=1&&t[i]-n>=1&&j<4)
                                dp[i][j+1][k][l+1][m+1][n+1]=max(dp[i][j+1][k][l+1][m+1][n+1],now);
                            if(i<34)
                                dp[i+1][j][k][m][n][0]=max(dp[i+1][j][k][m][n][0],now*(i>2?c[t[i-2]][l]:1)*qkpow(i>2?bp[i-2]:1,l));
                            if(i==34&&j==4&&k==1)
                                ans=max(ans,now*c[t[i-2]][l]*qkpow(bp[i-2],l)*c[t[i-1]][m]*qkpow(bp[i-1],m)*c[t[i]][n]*qkpow(bp[i],n));
                        }
                    }
                }
            }
        }
    }
    cout<<ans<<'\n';
}
int main()
{ 
    ios::sync_with_stdio(false);
    cin>>T;
    for(int i=1;i<=T;i++)
        c_in();
    return 0;
}

没错就是6维

猜你喜欢

转载自www.cnblogs.com/loney-s/p/12041057.html