zoukankan      html  css  js  c++  java
  • LOJ#3084. 「GXOI / GZOI2019」宝牌一大堆(递推)

    题面

    传送门

    题解

    为什么又是麻将啊啊啊!而且还是我最讨厌的爆搜类(dp)……

    首先国士无双和七对子是可以直接搞掉的,关键是剩下的,可以看成(1)个雀头加(4)个杠子或面子

    直接(dp),设(f[i][j][k][l][x][y])表示考虑前(i)种牌,以第(i-2)种牌为开头的顺子张数为(j),以(i-1)为开头的顺子张数为(k),以(i)开头的顺子张数为(l),杠子加面子总数为(x),雀头个数为(y),的最大权值

    注意一些边界条件,比方说以某一种牌开头的顺子选的不需要超过(2)个,因为如果选了(3)个完全可以拆成刻子。还有有的时候以某种牌为开头的顺子可能不合法。以及牌数加起来不能超

    这里其实可以把(l)这一维用滚动数组滚掉

    代码基本都是抄(fcw)

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define ll long long
    #define inline __inline__ __attribute__((always_inline))
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    const int N=55;
    inline ll max(R ll x,R ll y){return x>y?x:y;}
    ll bin[N],C[N][N];int a[N],b[N];
    inline ll ch(R int x,R int v){return C[a[x]][v]*bin[b[x]*v];}
    int id(char *w){
    	if(strlen(w+1)==2){
    		switch(w[2]){
    			case 'm':return w[1]-'0';
    			case 'p':return 9+w[1]-'0';
    			case 's':return 18+w[1]-'0';
    		}
    	}else{
    		switch(w[1]){
    			case 'E':return 28;
    			case 'W':return 29;
    			case 'N':return 30;
    			case 'S':return 31;
    			case 'Z':return 32;
    			case 'B':return 33;
    			case 'F':return 34;
    		}
    	}
    	return -1;
    }
    ll c[N];
    ll solve1(){
    	ll res=1;
    	fp(i,1,34)c[i]=ch(i,2);
    	sort(c+1,c+1+34);
    	fp(i,28,34)res*=c[i];return res*7;
    }
    int d[20]={0,1,9,10,18,19,27,28,29,30,31,32,33,34};
    ll solve2(){
    	ll res=0,tmp;
    	fp(i,1,13){
    		tmp=ch(d[i],2);
    		fp(j,1,13)if(i!=j)tmp*=ch(d[j],1);
    		cmax(res,tmp);
    	}return res*13;
    }
    ll f[35][3][3][5][2];
    ll solve3(){
    	memset(f,0,sizeof(f)),f[0][0][0][0][0]=1;
    	fp(i,0,34){
    		fp(j,0,2)if(!j||(i<=27&&i%9!=0&&i%9!=1)){
    			fp(k,0,2)if(!k||(i<=27&&i%9!=8&&i%9!=0))
    				if(a[i+1]>=j+k){
    					fp(x,j+k,4)fp(y,0,1)if(f[i][j][k][x][y]){
    							for(R int z=0;z<=2&&j+k+z<=a[i+1]&&x+z<=4;++z)
    								for(R int w=0;j+k+z+w*3<=a[i+1]&&x+z+w<=4;++w){
    									int t=j+k+z+w*3;
    									cmax(f[i+1][k][z][x+z+w][y],f[i][j][k][x][y]*ch(i+1,t));
    									if(!y&&t+2<=a[i+1])cmax(f[i+1][k][z][x+z+w][1],f[i][j][k][x][y]*ch(i+1,t+2));
    								}
    							if(a[i+1]-j-k==4&&x<4)cmax(f[i+1][k][0][x+1][y],f[i][j][k][x][y]*ch(i+1,4));
    						}
    				}
    		}
    	}
    	return f[34][0][0][4][1];
    }
    void init(){
    	bin[0]=1;fp(i,1,18)bin[i]=bin[i-1]<<1;
    	fp(i,0,4){
    		C[i][0]=1;
    		fp(j,1,i)C[i][j]=C[i-1][j-1]+C[i-1][j];
    	}
    }
    char w[15];
    void solve(){
    	fp(i,1,34)a[i]=4,b[i]=0;
    	while(true){
    		scanf("%s",w+1);
    		if(w[1]=='0')break;
    		--a[id(w)];
    	}
    	while(true){
    		scanf("%s",w+1);
    		if(w[1]=='0')break;
    		b[id(w)]=1;
    	}
    	printf("%lld
    ",max(solve1(),max(solve2(),solve3())));
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	int T;scanf("%d",&T);init();
    	while(T--)solve();
    	return 0;
    }
    
  • 相关阅读:
    pat 甲级 1065. A+B and C (64bit) (20)
    pat 甲级 1064. Complete Binary Search Tree (30)
    pat 甲级 1010. Radix (25)
    pat 甲级 1009. Product of Polynomials (25)
    pat 甲级 1056. Mice and Rice (25)
    pat 甲级 1078. Hashing (25)
    pat 甲级 1080. Graduate Admission (30)
    pat 甲级 团体天梯 L3-004. 肿瘤诊断
    pat 甲级 1099. Build A Binary Search Tree (30)
    Codeforce 672B. Different is Good
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10719609.html
Copyright © 2011-2022 走看看