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;
    }
    
  • 相关阅读:
    Pivot Table 实现详解(一)
    VSTS 离线源码版本辅助工具
    早上发现还是问题不断
    VSTS 离线源码版本辅助工具源码
    C#单元测试
    长沙招聘若干 ASP.NET 开发人员(长期有效)
    解析判定数据有效性表达式的存储过程 for SQLServer
    提高 SNAP 网页预览图的采集速度
    用了2年多快3年的老ASUS本子出了点小问题了
    模拟一下细胞的繁殖(CSDN号召帖)
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10719609.html
Copyright © 2011-2022 走看看