[GXOI/GZOI2019]宝牌一大堆(dp)

[GXOI/GZOI2019]宝牌一大堆(dp)

luogu     bzoj

这个麻将题还算挺友善的,比隔壁zjoi的要好得多。。。

比较正常的做法是五维dp

但事实上六维dp也是完全不会被卡的

七对子选权值最高的七个,国士无双直接$13^2$暴力

$dp[i][j][0/1][k][l][m]$表示枚举到了第i张牌,已经凑了j个面子,有无雀头,第i张牌已经用了k张,第i+1张牌用了l张,第i+2张牌用了m张,直接暴力转移。。。

然后你会得到50...

当然需要优化。

优化1:

枚举到dp值为0的直接continue,这样的不合法牌型有很多可以直接跳过。

优化2:

l和m只枚举到2,原因?如果枚举到三个顺子的话那么我们完全可以用三个刻子等效替代。

优化3:

不需要考虑杠。

原因?

$C_{4}^{3}=4$,$C_{4}^{4}=1$

就算这张牌是宝牌选刻子也必然优于杠子

代码就领略一下精神吧(

 

  1 #include<cstdio>
  2 #include<algorithm>
  3 #include<queue>
  4 #define d01(x) for(int x=0;x<2;x++)
  5 using std::priority_queue;
  6 using std::max;
  7 typedef long long lint;
  8 char si[3];
  9 void dm(lint &kk,lint l){kk=max(kk,l);}
 10 
 11 int a[35],dora[35];//1~9,10~18,19~27,28,29,30,31,32,33,34
 12 lint dp[36][5][2][5][3][3];
 13 lint dg[36];
 14 lint ans;
 15 int c[5][5]={
 16     1,0,0,0,0,
 17     1,1,0,0,0,
 18     1,2,1,0,0,
 19     1,3,3,1,0,
 20     1,4,6,4,1
 21 };
 22 int yaoku[15]={0,1,9,10,18,19,27,28,29,30,31,32,33,34};
 23 bool isyaoku[35]={0,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1};
 24 bool tail[35]={0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1};
 25 void kokushi()
 26 {
 27     int x;
 28     for(int i=1;i<=13;i++)
 29     {
 30         x=yaoku[i];
 31         lint tmp=13;
 32         tmp*=c[a[x]][2]*dora[x]*dora[x];
 33         for(int j=1;j<=13;j++)
 34         {
 35             if(i==j) continue;x=yaoku[j];
 36             tmp*=a[x]*dora[x];
 37         }
 38         ans=max(ans,tmp);
 39     }
 40 }
 41 priority_queue<int> q;
 42 void chitoi()
 43 {
 44     lint tmp=7;
 45     for(int i=1;i<=34;i++) q.push(c[a[i]][2]*dora[i]*dora[i]);
 46     int g;
 47     for(int i=1;i<=7;i++)
 48     {
 49         g=q.top();
 50         q.pop();
 51         tmp*=g;
 52     }
 53     ans=max(ans,tmp);
 54     while(!q.empty()) q.pop();
 55 }
 56 
 57 
 58 void clr()
 59 {
 60     for(int i=1;i<=35;i++)
 61     {
 62         dg[i]=0;
 63         for(int j=0;j<=4;j++)
 64         {
 65             for(int k=0;k<=4;k++)
 66             {
 67                 for(int l=0;l<=2;l++)
 68                 {
 69                     for(int m=0;m<=2;m++)
 70                     dp[i][j][0][k][l][m]=dp[i][j][1][k][l][m]=0;
 71                 }
 72             }
 73         }
 74     }
 75     for(int i=1;i<=34;i++) a[i]=4,dora[i]=1;
 76     ans=0;
 77     dp[1][0][0][0][0][0]=1;
 78 }
 79 int main()
 80 {
 81     int T;
 82     scanf("%d",&T);
 83     while(T--)
 84     {
 85         clr();
 86         while(1)
 87         {
 88             scanf("%s",si);
 89             if(si[0]=='0') break;
 90             else if(si[1]=='p') a[si[0]-'0']--;
 91             else if(si[1]=='s') a[si[0]-'0'+9]--;
 92             else if(si[1]=='m') a[si[0]-'0'+18]--;
 93             else if(si[0]=='E') a[28]--;
 94             else if(si[0]=='S') a[29]--;
 95             else if(si[0]=='W') a[30]--;
 96             else if(si[0]=='N') a[31]--;
 97             else if(si[0]=='B') a[32]--;
 98             else if(si[0]=='F') a[33]--;
 99             else if(si[0]=='Z') a[34]--;
100         }
101         while(1)
102         {
103             scanf("%s",si);
104             if(si[0]=='0') break;
105             else if(si[1]=='p') dora[si[0]-'0']=2;
106             else if(si[1]=='s') dora[si[0]-'0'+9]=2;
107             else if(si[1]=='m') dora[si[0]-'0'+18]=2;
108             else if(si[0]=='E') dora[28]=2;
109             else if(si[0]=='S') dora[29]=2;
110             else if(si[0]=='W') dora[30]=2;
111             else if(si[0]=='N') dora[31]=2;
112             else if(si[0]=='B') dora[32]=2;
113             else if(si[0]=='F') dora[33]=2;
114             else if(si[0]=='Z') dora[34]=2;
115         }
116         kokushi();//国士无双 
117         chitoi();//七对子 
118         for(int i=1;i<=34;i++)
119         {
120             for(int j=0;j<=4;j++)
121             {
122                 for(int k=0;k<=4;k++)
123                 {
124                     for(int l=0;l<=2;l++)
125                     {
126                         for(int m=0;m<=2;m++)
127                         {
128                             if(!dp[i][j][0][k][l][m]&&!dp[i][j][1][k][l][m]) continue;
129                             if(a[i]-k>=2) dm(dp[i][j][1][k+2][l][m],dp[i][j][0][k][l][m]/c[a[i]][k]*c[a[i]][k+2]*dora[i]*dora[i]);
130                             //雀头 
131                             if(j<4)
132                             {
133                                 if(a[i]-k>=3) d01(o) dm(dp[i][j+1][o][k+3][l][m],dp[i][j][o][k][l][m]/c[a[i]][k]*c[a[i]][k+3]*dora[i]*dora[i]*dora[i]);
134                                 //刻子 
135                                 if((!tail[i])&&a[i]-k>0&&a[i+1]-l>0&&a[i+2]-m>0&&l!=2&&m!=2)
136                                     d01(o) dm(dp[i][j+1][o][k+1][l+1][m+1],dp[i][j][o][k][l][m]/c[a[i]][k]*c[a[i]][k+1]*dora[i]/c[a[i+1]][l]*c[a[i+1]][l+1]*dora[i+1]/c[a[i+2]][m]*c[a[i+2]][m+1]*dora[i+2]);
137                                 //顺子 
138                             }
139                             dm(dp[i+1][j][0][l][m][0],dp[i][j][0][k][l][m]);
140                             dm(dp[i+1][j][1][l][m][0],dp[i][j][1][k][l][m]);
141                             //转移 
142                             if(j==4) dg[i]=max(dg[i],dp[i][j][1][k][l][m]);
143                         }
144                     }
145                 }
146             }
147         }
148         for(int i=1;i<=35;i++) ans=max(ans,dg[i]);
149         printf("%lld\n",ans);
150     }
151     return 0;
152 }
Orz
posted @ 2019-06-18 19:38  RikukiIX  阅读(207)  评论(0编辑  收藏  举报