zoukankan      html  css  js  c++  java
  • 「GXOI / GZOI2019」宝牌一大堆

    「GXOI / GZOI2019」宝牌一大堆

    麻将.jpg

    观察牌型和计算方法可知,选择一个杠与选择一个面子对于牌型的贡献是等价的

    而选择一个杠的答案一定没有选择一个刻子优,因此是没有任何意义的

    除去 "七对子" "国士无双" 的特殊情况后,此外的情况就是选择 4个面子 + 1个雀头

    容易想到对于每个花色dp得到选择(i)个面子(j)个雀头的答案,然后背包合并

    为了(dp)顺子的情况,可以存储前面两个位置作为顺子头的个数

    (dp_{i,j,a,b})表示当前选了(i)个面子,(j)个雀头,上两个位置选了(a)个顺子,上一个位置选了(b)个顺子

    暴力维护dp即可

    const int INF=1e9+10;
    
    int min(int x,int y,int z){ return min(min(x,y),z); }
    
    int n,m;
    int C[5][5],c[4][12],mk[4][12];
    ll ans,val[5][2];
    
    void Check7(){
    	static int val[40],cnt;
    	cnt=0;
    	rep(i,0,3) rep(j,0,9) if(c[i][j]>=2) val[++cnt]=C[c[i][j]][2]<<(mk[i][j]*2);
    	if(cnt<7) return;
    	sort(val+1,val+cnt+1,greater<int>());
    	ll res=7;
    	rep(i,1,7) res*=val[i];
    	cmax(ans,res);
    }
    
    void Check13(){
    	ll res=13,x=0,y=0;
    	auto chk=[&](ll a,ll b) {
    		if(!x) x=a,y=b;
    		if(x*b<a*y) x=a,y=b;
    	};
    	rep(i,0,2) {
    		if(!c[i][0] || !c[i][8]) return;
    		res*=c[i][0]*c[i][8];
    		res<<=(mk[i][0]+mk[i][8]);
    		if(c[i][0]>=2) chk(C[c[i][0]][2]<<(mk[i][0]*2),c[i][0]<<mk[i][0]);
    		if(c[i][8]>=2) chk(C[c[i][8]][2]<<(mk[i][8]*2),c[i][8]<<mk[i][8]);
    	}
    	rep(i,0,6) {
    		if(!c[3][i]) return;
    		res<<=mk[3][i];
    		res*=c[3][i];
    		if(c[3][i]>=2) chk(C[c[3][i]][2]<<(mk[3][i]*2),c[3][i]<<mk[3][i]);
    	}
    	if(!x) return;
    	cmax(ans,res*x/y);
    }
    
    void Work(int *cnt,int *mk,ll res[5][2]){
    	static ll dp[2][5][2][5][5],w[5];
    	int cur=0;
    	memset(dp,0,sizeof dp),dp[cur][0][0][0][0]=1;
    	rep(t,0,8) {
    		int x=cnt[t]; ll val;
    		memset(dp[!cur],0,sizeof dp[!cur]);
    		rep(i,0,x) w[i]=C[x][i]<<(mk[t]*i);
    		rep(i,0,4) rep(j,0,1) rep(a,0,x) rep(b,0,x-a) if((val=dp[cur][i][j][a][b])) {
    			int d=a+b,y=x-d,u=min(cnt[t+1]-b,cnt[t+2]);
    
    			rep(k,0,min(3-i,y-3,u))
    				cmax(dp[!cur][i+k+1][j][b][k],val*w[d+k+3]); // 刻 + 顺
    
    			rep(k,0,min(4-i,y,u))
    				cmax(dp[!cur][i+k][j][b][k],val*w[d+k]); // 顺
    
    			if(j) continue;
    			rep(k,0,min(4-i,y-2,u))
    				cmax(dp[!cur][i+k][j+1][b][k],val*w[d+k+2]); // 雀 + 顺
    		}
    		cur^=1;
    	}
    	drep(i,4,0) drep(j,1,0) if(res[i][j]) {
    		rep(a,0,4-i) rep(b,0,1-j) 
    			if(dp[cur][a][b][0][0]) 
    				cmax(res[i+a][j+b],res[i][j]*dp[cur][a][b][0][0]);
    	}
    }
    
    Pii Read(){
    	static char O[5];
    	scanf("%s",O);
    	if(*O=='0') return mp(-1,0);
    	if(isalpha(*O)) {
    		if(*O=='E') return mp(3,0);
    		if(*O=='S') return mp(3,1);
    		if(*O=='W') return mp(3,2);
    		if(*O=='N') return mp(3,3);
    		if(*O=='Z') return mp(3,4);
    		if(*O=='B') return mp(3,5);
    		if(*O=='F') return mp(3,6);
    		return mp(-1,-1);
    	}
    	if(O[1]=='m') return mp(0,*O-'1');
    	if(O[1]=='p') return mp(1,*O-'1');
    	if(O[1]=='s') return mp(2,*O-'1');
    	return mp(-1,-1);
    }
    
    void Solve(){
    	ans=0,memset(val,0,sizeof val),memset(mk,0,sizeof mk),val[0][0]=1;
    	rep(i,0,2) rep(j,0,8) c[i][j]=4;
    	rep(i,0,6) c[3][i]=4;
    	while(1) {
    		Pii T=Read();
    		if(T.first==-1) break;
    		c[T.first][T.second]--;
    	}
    	while(1) {
    		Pii T=Read();
    		if(T.first==-1) break;
    		mk[T.first][T.second]=1;
    	}
    	Check7(),Check13();
    	rep(i,0,2) Work(c[i],mk[i],val);
    	rep(i,0,6) {
    		static ll w[5];
    		int x=c[3][i];
    		rep(j,0,x) w[j]=C[x][j]<<(j*mk[3][i]);
    		drep(a,4,0) drep(b,1,0) if(val[a][b]) {
    			if(b<1 && x>=2) cmax(val[a][b+1],val[a][b]*w[2]); // 雀
    			if(a<4 && x>=3) cmax(val[a+1][b],val[a][b]*w[3]); // 刻
    			if(a<4 && x>=4) cmax(val[a+1][b],val[a][b]*w[4]); // 杠
    		}
    	}
    	cmax(ans,val[4][1]);
    	printf("%lld
    ",ans);
    }
    
    int main(){
    	rep(i,0,4) rep(j,C[i][0]=1,i) C[i][j]=C[i-1][j]+C[i-1][j-1];
    	int T; scanf("%d",&T);
    	while(T--) Solve();
    }
    
  • 相关阅读:
    java堆和栈的区别
    什么是java 序列化,如何实现java 序列化?
    HashMap和Hashtable的区别
    [LeetCode] 548. Split Array with Equal Sum 分割数组成和相同的子数组
    [LeetCode] 533. Lonely Pixel II 孤独的像素 II
    [LeetCode] 531. Lonely Pixel I 孤独的像素 I
    [LeetCode] 205. Isomorphic Strings 同构字符串
    [LeetCode] 351. Android Unlock Patterns 安卓解锁模式
    Python list、tuple、dict区别
    Minimum number of swaps required to sort an array
  • 原文地址:https://www.cnblogs.com/chasedeath/p/14528028.html
Copyright © 2011-2022 走看看