zoukankan      html  css  js  c++  java
  • Solution -「GXOI / GZOI 2019」宝牌一大堆

    Description

    Link.

    Summarizing the fucking statement is the last thing in the world I ever want to do.

    Solution

    我们来重新描述一些概念:

    • 数字牌:筒条万。
    • 顺子:(3) 张连续的数字牌。(面子)
    • 雀头:(2) 张完全一样的牌。
    • 刻子:(3) 张完全一样的牌。(面子)
    • 杠子:(4) 张完全一样的牌。

    观察发现:杠子在除了 (14) 张牌胡牌情况以外的胡牌情况都出现了,于是又发现:(inom{4}{3}>inom{4}{4})

    于是:

    • 对于胡牌的形式,我们只需要考虑「(3 imes4+2)」「七对子」和「国士无双」。

    于是我们只需要三种情况取最大即可。

    1. 「七对子」只需要把所有牌型的贡献拉出来,取前 (7) 个最大的乘起来即可。

    2. 「国士无双」枚举谁来做 (2) 个的那个,然后取最大。

    3. (3 imes4+2)

    (qquad) 考虑这样一个 DP,设:(f(i,j,k,a,b,c)) 为前 (i) 个数,(j) 个面子,(k) 个雀头,第 (i) / (i+1) / (i+2) 张牌用了 (a) / (b) / (c) 张的最优答案((kin{0,1}))。

    (qquad) (qquad) 1. 对于雀头:

    [f(i,j,1,a+2,b,c)=max{frac{f(i,j,0,a,b,c) imes ext{calc}(i,a+2)}{ ext{calc}(i,a)}} ]

    (qquad) (qquad) (qquad) 其中 ( ext{calc}(x,y)) 为第 (x) 张牌,在手牌中需要出现 (y) 次,此时对答案的贡献。

    (qquad) (qquad) (qquad) 方程的意义即:去掉把第 (i) 种牌之前的贡献,再算上现在算作雀头的贡献。

    (qquad) (qquad) 2. 对于刻子:

    [f(i,j+1,0 ext{ or }1,a+3,b,c)=max{frac{f(i,j,0 ext{ or }1,a,b,c) imes ext{calc}(i,a+3)}{ ext{calc}(i,a)}} ]

    (qquad) (qquad) (qquad) 基本同上。

    (qquad) (qquad) 3. 对于顺子:

    [f(i,j+1,0 ext{ or }1,a+1,b+1,c+1)=max{frac{f(i,j,0 ext{ or }1,a,b,c) imes ext{calc}(i,a+1) imes ext{calc}(i+1,b+1) imes ext{calc}(i+2,c+1)}{ ext{calc}(i,a) imes ext{calc}(i+1,b) imes ext{calc}(i+2,c)}} ]

    (qquad) (qquad) (qquad) 完全同理。

    然后就完了。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const LL koshi[15]={0,1,9,10,18,19,27,28,29,30,31,32,33,34}; // the cards that Kokushimusou needs
    const bool chunko[36]={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}; // the cards which are able to be jyunko
    LL getCard()
    {
    	static char s[10];
    	scanf("%s",s+1);
    	if(s[1]=='0')	return -1;
    	else if(!isdigit(s[1]))
    	{
    		if(s[1]=='E')	return 28;
    		else if(s[1]=='S')	return 29;
    		else if(s[1]=='W')	return 30;
    		else if(s[1]=='N')	return 31;
    		else if(s[1]=='Z')	return 32;
    		else if(s[1]=='B')	return 33;
    		else	return 34;
    	}
    	else
    	{
    		if(s[2]=='m')	return s[1]-'0';
    		else if(s[2]=='p')	return s[1]-'0'+9;
    		else	return s[1]-'0'+18;
    	}
    }
    LL t,comb[10][10],cnt[40],trs[40],f[40][5][5][5][5][5];
    #define calc(x,f) (((cnt[x])<(f)?0:comb[cnt[x]][f])*(trs[x]?(1<<(f)):1))
    LL onesolve() // Seven Pairs
    {
    	vector<LL> pri;
    	for(LL i=1;i<=34;++i)	if(cnt[i]>=2)	pri.push_back(calc(i,2));
    	sort(pri.begin(),pri.end(),greater<LL>());
    	if(pri.size()<size_t(7))	return 0;
    	else
    	{
    		LL res=7;
    		for(LL i=0;i<7;++i)	res*=pri[i];
    		return res;
    	}
    }
    LL anosolve() // Kokushimusou
    {
    	LL flag=0;
    	for(LL i=1;i<=13;++i)
    	{
    		if(cnt[koshi[i]]>=2)	flag=1;
    		if(cnt[koshi[i]]==0)	return 0;
    	}
    	if(flag)
    	{
    		LL res=0;
    		for(LL i=1;i<=13;++i)
    		{
    			LL tmp=13;
    			if(cnt[koshi[i]]>=2)
    			{
    				for(LL j=1;j<=13;++j)	tmp*=calc(koshi[j],(i==j)+1);
    			}
    			res=max(res,tmp);
    		}
    		return res;
    	}
    	else	return 0;
    }
    void getmax(LL &one,LL ano){one=max(one,ano);}
    LL exsolve() // 3x4+2
    {
    	#define f(i,j,k,a,b,c) (f[i][j][k][a][b][c])
    	f(1,0,0,0,0,0)=1;
    	for(LL i=1;i<=34;++i)
    	{
    		for(LL j=0;j<=4;++j)
    		{
    			for(LL a=0;a<=4;++a)
    			{
    				for(LL b=0;b<=2;++b)
    				{
    					for(LL c=0;c<=2;++c)
    					{
    						if(cnt[i]-a>=2)	getmax(f(i,j,1,a+2,b,c),f(i,j,0,a,b,c)/calc(i,a)*calc(i,a+2));
    						if(j^4)
    						{
    							if(cnt[i]-a>=3)
    							{
    								getmax(f(i,j+1,0,a+3,b,c),f(i,j,0,a,b,c)/calc(i,a)*calc(i,a+3));
    								getmax(f(i,j+1,1,a+3,b,c),f(i,j,1,a,b,c)/calc(i,a)*calc(i,a+3));
    							}
    							if(chunko[i]&&cnt[i]-a>=1&&cnt[i+1]-b>=1&&cnt[i+2]-c>=1&&(b^2)&&(c^2))
    							{
    								getmax(f(i,j+1,0,a+1,b+1,c+1),f(i,j,0,a,b,c)/calc(i,a)/calc(i+1,b)/calc(i+2,c)*calc(i,a+1)*calc(i+1,b+1)*calc(i+2,c+1));
    								getmax(f(i,j+1,1,a+1,b+1,c+1),f(i,j,1,a,b,c)/calc(i,a)/calc(i+1,b)/calc(i+2,c)*calc(i,a+1)*calc(i+1,b+1)*calc(i+2,c+1));
    							}
    						}
    						getmax(f(i+1,j,0,b,c,0),f(i,j,0,a,b,c));
    						getmax(f(i+1,j,1,b,c,0),f(i,j,1,a,b,c));
    					}
    				}
    			}
    		}
    	}
    	LL res=0;
    	for(LL i=1;i<=34;++i)
    	{
    		for(LL a=0;a<=4;++a)
    		{
    			for(LL b=0;b<=2;++b)
    			{
    				for(LL c=0;c<=2;++c)	getmax(res,f(i,4,1,a,b,c));
    			}
    		}
    	}
    	#undef f
    	return res;
    }
    int main()
    {
    	for(LL i=0;i<=4;++i)	comb[i][0]=comb[i][i]=1;
    	for(LL i=1;i<=4;++i)	for(LL j=1;j<i;++j)	comb[i][j]=comb[i-1][j-1]+comb[i-1][j];
    	scanf("%lld",&t);
    	while(t--)
    	{
    		memset(f,0,sizeof(f));
    		for(LL i=1;i<=34;++i)	cnt[i]=4,trs[i]=0;
    		LL tmp=getCard();
    		while(~tmp)	--cnt[tmp],tmp=getCard();
    		tmp=getCard();
    		while(~tmp)	trs[tmp]=1,tmp=getCard();
    		printf("%lld
    ",max(max(onesolve(),anosolve()),exsolve()));
    	}
    	return 0;
    }
    
  • 相关阅读:
    图的广度优先遍历
    马踏棋盘算法(骑士周游问题) 数据结构和算法60
    马踏棋盘算法(骑士周游问题) 数据结构和算法60
    图的遍历(广度优先遍历) 数据结构和算法61
    图的遍历(广度优先遍历) 数据结构和算法61
    从零开始学习Sencha Touch MVC应用之十
    从零开始学习Sencha Touch MVC应用之十一
    从零开始学习Sencha Touch MVC应用之七
    从零开始学习Sencha Touch MVC应用之六
    从零开始学习Sencha Touch MVC应用之十三
  • 原文地址:https://www.cnblogs.com/orchid-any/p/14507610.html
Copyright © 2011-2022 走看看