题目
思路
这道题主要是状态不好想和题目不好理解
如果你和笔者一样没有接触过麻将
我们首先将整个麻将进行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维
原文地址:https://www.cnblogs.com/loney-s/p/12041057.html