1. 程式人生 > >[GX/GZOI2019]寶牌一大堆(DP)

[GX/GZOI2019]寶牌一大堆(DP)

++ aps splay scanf pen turn sed 直接 圖片

出這種麻將題有意思嗎?

乍看很難實則很水,就是麻將式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()))); } }
View Code

[GX/GZOI2019]寶牌一大堆(DP)