zoukankan      html  css  js  c++  java
  • 【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
    ",ans);
    	}
    }
    
  • 相关阅读:
    事件对象3
    事件对象2
    事件对象1
    编码、摘要、加密
    身份证号码的组成
    Oracle的TO_CHAR()格式化数字为百分数的字符串
    转载和补充:Oracle中的一些特殊字符
    linux Shell(待学)
    linux 管道相关命令(待学)
    linux用户权限、系统信息相关命令(待学)
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10733866.html
Copyright © 2011-2022 走看看