【BZOJ5503】[GXOI/GZOI2019]宝牌一大堆(动态规划)

【BZOJ5503】[GXOI/GZOI2019]宝牌一大堆(动态规划)

题面

BZOJ
洛谷

题解

首先特殊牌型直接特判。
然后剩下的部分可以直接\(dp\),直接把所有可以存的全部带进去大力\(dp\)就行了。
发现每多一张牌胡的本质就是把一个刻字换成杠子,所以这两个东西记录在一起就行了。
那么状态就是\(f[i][0/1/2/3/4][0/1/2][0/1/2][0/1]\)
分别表示刻字、杠子、顺子的数量,\(i-1,i,i+1\)的顺子数量,\(i,i+1,i+2\)的顺子的数量,以及是否已经有对子。
转移比较容易。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<vector>
using namespace std;
#define ll long long
#define MAX 140
int Read()
{
	char ch[3];scanf("%s",ch);
	if(ch[0]=='E')return 28;if(ch[0]=='S')return 29;
	if(ch[0]=='W')return 30;if(ch[0]=='N')return 31;
	if(ch[0]=='Z')return 32;if(ch[0]=='B')return 33;
	if(ch[0]=='F')return 34;if(ch[0]=='0')return 0;
	int x=ch[0]-48;if(ch[1]=='p')x+=9;if(ch[1]=='s')x+=18;
	return x;
}
ll C[MAX][MAX];
int n,s[MAX];bool book[MAX];
ll f[35][6][3][3][2];
int pre[14]={0,1,9,10,18,19,27,28,29,30,31,32,33,34};
int bin[10]={1,2,4,8,16,32,64,128,256,512};
void cmax(ll &x,ll y){x=max(x,y);}
int main()
{
	for(int i=0;i<10;++i)C[i][0]=1;
	for(int i=1;i<10;++i)
		for(int j=1;j<=i;++j)C[i][j]=C[i-1][j]+C[i-1][j-1];
	int T,x;scanf("%d",&T);
	while(T--)
	{
		for(int i=1;i<=34;++i)s[i]=4,book[i]=false;
		while((x=Read()))s[x]-=1;
		while((x=Read()))book[x]=true;
		ll ans=0;
		//Task1
		{
			bool fl=true;int mx=0;ll ret=1;
			for(int i=1;i<=13;++i)
				if(!s[pre[i]]){fl=false;break;}
				else mx=max(mx,(s[pre[i]]-1)*(book[pre[i]]?2:1)),ret=ret*(book[pre[i]]?2:1)*s[pre[i]];
			if(fl)ret=ret*mx*13/2,ans=max(ans,ret);
		}
		//Task2
		{
			vector<int> val;
			for(int i=1;i<=34;++i)
				if(s[i]>=2)val.push_back((book[i]?4:1)*(s[i]*(s[i]-1)/2));
			sort(val.begin(),val.end());
			if(val.size()>=7)
			{
				ll ret=1;
				for(int i=7;i;--i)ret*=val.back(),val.pop_back();
				ans=max(ans,ret*7);
			}
		}
		//Task3
		{
			memset(f,0,sizeof(f));
			f[0][0][0][0][0]=1;
			for(int i=1;i<=34;++i)
				for(int j=0;j<5;++j)
					for(int k=0;k<3&&j+k<=4&&k<=s[i];++k)
					{
						if(k>0&&(i==10||i==19||i>=28||i==11||i==20))break;
						for(int l=0;l<3&&j+k+l<=4&&k+l<=s[i];++l)
						{
							if(l>0&&(l==9||i==18||i==27||i==10||i==19||i>=28))break;
							if(!f[i-1][j][k][l][0]&&!f[i-1][j][k][l][1])continue;
							for(int m=0;k+l+m<=s[i]&&m<3;++m)
							{
								if(m>0&&(i==9||i==18||i>=27))continue;
								if(s[i]>=4+k+l+m)
								{
									cmax(f[i][j+1+k][l][m][0],(book[i]?16:1)*f[i-1][j][k][l][0]);
									cmax(f[i][j+1+k][l][m][1],(book[i]?16:1)*f[i-1][j][k][l][1]);
								}
								if(s[i]>=3+k+l+m)
								{
									cmax(f[i][j+1+k][l][m][0],(book[i]?bin[3+k+l+m]:1)*C[s[i]][3+k+l+m]*f[i-1][j][k][l][0]);
									cmax(f[i][j+1+k][l][m][1],(book[i]?bin[3+k+l+m]:1)*C[s[i]][3+k+l+m]*f[i-1][j][k][l][1]);
								}
								if(s[i]>=2+k+l+m)
								{
									cmax(f[i][j+k][l][m][1],(book[i]?bin[2+k+l+m]:1)*C[s[i]][2+k+l+m]*f[i-1][j][k][l][0]);
								}
								if(s[i]>=k+l+m)
								{
									cmax(f[i][j+k][l][m][0],(book[i]?bin[k+l+m]:1)*C[s[i]][k+l+m]*f[i-1][j][k][l][0]);
									cmax(f[i][j+k][l][m][1],(book[i]?bin[k+l+m]:1)*C[s[i]][k+l+m]*f[i-1][j][k][l][1]);
								}
							}
						}
					}
			ans=max(ans,f[34][4][0][0][1]);
		}
		printf("%lld\n",ans);
	}
}
posted @ 2019-04-19 09:08  小蒟蒻yyb  阅读(369)  评论(0编辑  收藏  举报