[GX/GZOI2019]宝牌一大堆(DP)
出这种麻将题有意思吗?
乍看很难实则很水,就是麻将式DP,想必大家很熟悉了吧。首先把“国士无双”和“七对子”两种牌型判掉,然后观察牌胡的形式,发现每多一张牌实际上就是把1个面子变成1个杠子,然后可以直接DP啦!f[i][j][k][p][q]表示到第i种牌型,(i-2,i-1,i)有j个,(i-1,i,i+1)有k个,然后面子+杠子共p个,q=0/1表示是否有对子的最大值,暴力转移即可。
不知道为啥,luogu满分,LOJ RE成0分,这种垃圾题,不想管了。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int id[14]={0,1,2,3,4,5,6,7,8,16,17,25,26,34}; int mp[200],cnt[35],vis[35],c[5][5]; ll f[35][3][3][5][2],g[35][15]; ll upd(ll&x,ll y){x=x>y?x:y;} int read() { char str[5];scanf("%s",str); if(str[0]=='0')return 0; if(strlen(str)==1)return mp[str[0]]; if(str[1]=='m')return 7+str[0]-'0'; if(str[1]=='p')return 16+str[0]-'0'; return 25+str[0]-'0'; } ll cal(int x,int y){return(1ll<<(vis[x]?y:0))*c[cnt[x]][y];} ll gsws() { memset(g,0,sizeof g); g[0][0]=1; for(int i=0;i<13;i++) for(int j=0;j<=14;j++) for(int k=1;k<=cnt[id[i+1]]&&k<=2&&j+k<=14;k++) upd(g[i+1][j+k],g[i][j]*cal(id[i+1],k)); return 13*g[13][14]; } ll qdz() { memset(g,0,sizeof g); g[0][0]=1; for(int i=0;i<34;i++) for(int j=0;j<=7;j++) { upd(g[i+1][j],g[i][j]); if(j<7)upd(g[i+1][j+1],g[i][j]*cal(i+1,2)); } return 7*g[34][7]; } ll solve() { memset(f,0,sizeof f); f[0][0][0][0][0]=1; for(int i=0;i<34;i++) for(int j=0;j<3;j++) if(!j||i>7&&(i-7)%9!=0&&(i-7)%9!=1) for(int k=0;k<3;k++) if(!k||i>7&&(i-7)%9!=8&&(i-7)%9!=0&&cnt[i+1]>=j+k) for(int p=j+k;p<=4;p++) for(int q=0;q<=1;q++) if(f[i][j][k][p][q]) { for(int a=0;a<=2&&j+k+a<=cnt[i+1]&&p+a<=4;a++) for(int b=0;j+k+a+b*3<=cnt[i+1]&&p+a+b<=4;b++) { upd(f[i+1][k][a][p+a+b][q],f[i][j][k][p][q]*cal(i+1,j+k+a+b*3)); if(!q&&j+k+a+b*3+2<=cnt[i+1]) upd(f[i+1][k][a][p+a+b][1],f[i][j][k][p][q]*cal(i+1,j+k+a+b*3+2)); } if(cnt[i+1]-j-k==4&&p<4)upd(f[i+1][k][0][p+1][q],f[i][j][k][p][q]*cal(i+1,4)); } return f[34][0][0][4][1]; } int main() { mp['E']=1,mp['S']=2,mp['W']=3,mp['N']=4,mp['Z']=5,mp['B']=6,mp['F']=7; for(int i=0;i<=4;i++) { c[i][0]=1; for(int j=1;j<=i;j++)c[i][j]=c[i-1][j]+c[i-1][j-1]; } int T,v;scanf("%d",&T); while(T--) { for(int i=1;i<=34;i++)cnt[i]=4,vis[i]=0; while(v=read())cnt[v]--; while(v=read())vis[v]=1; printf("%lld\n",max(solve(),max(qdz(),gsws()))); } }