原题传送门

希望这题不会让你对麻将的热爱消失殆尽

我们珂以统计每种牌出现的次数,不需要统计是第几张牌

判一副牌能不能和,类似这道题

对于这题:

设\(f[i][j][k][0/1]\)表示前\(i\)种牌,顺子\((i-1,i,i+1)\)出现了\(j\)次,顺子\((i,i+1,i+2)\)出现了\(k\)次,有/没有雀头的最多面子数。转移比较简单

我们珂以发现\(j\)这维不太重要,强制dp值不超过\(4\)(超过\(4\)也没有用),雀头数不超过\(7\)(类似),爆搜珂以搜出本质不同的状态一共有\(2091\)个

珂以在每个状态珂以在后面加\(x \in [0,4]\)张点数+1的牌,这珂以构成一个自动机,我们叫她和牌自动机

我们每得到一个状态,珂以在和牌自动机上走,判断是否能和

我们设\(dp[i][j][k]\)表示看到前\(i\)种牌,在和牌自动机上的\(j\)状态,已经摸了\(k\)张牌,不胡的种类数,最后算一下期望就珂以了

我们珂以用滚动数组把\(i\)滚掉优化空间

#include <bits/stdc++.h>
#define mod 998244353
#define N 405
#define getchar nc
using namespace std;
inline char nc(){
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int read()
{
register int x=0,f=1;register char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
return x*f;
}
inline void write(register int x)
{
if(!x)putchar('0');if(x<0)x=-x,putchar('-');
static int sta[20];register int tot=0;
while(x)sta[tot++]=x%10,x/=10;
while(tot)putchar(sta[--tot]+48);
}
inline int Min(register int a,register int b)
{
return a<b?a:b;
}
inline int Max(register int a,register int b)
{
return a>b?a:b;
}
struct node{
int f[3][3][2],cnt;
inline void init()
{
memset(f,-1,sizeof(f));
f[0][0][0]=cnt=0;
}
inline int hu()
{
if(cnt>=7)
return 1;
for(register int i=0;i<3;++i)
for(register int j=0;j<3;++j)
if(f[i][j][1]>=4)
return 1;
return 0;
}
}rt,S[2100];
bool operator < (node a,node b){
if(a.cnt!=b.cnt)
return a.cnt<b.cnt;
for(register int i=0;i<3;++i)
for(register int j=0;j<3;++j)
for(register int k=0;k<2;++k)
if(a.f[i][j][k]!=b.f[i][j][k])
return a.f[i][j][k]<b.f[i][j][k];
return 0;
}
int tot=0;
map<node,int> ma;
inline node trans(register node u,register int w)
{
node v;
v.init();
v.cnt=Min(u.cnt+(w>=2),7);
for(register int i=0;i<3;++i)
for(register int j=0;j<3;++j)
{
if(~u.f[i][j][0])
{
for(register int k=0;k<3&&i+j+k<=w;++k)
v.f[j][k][0]=Max(v.f[j][k][0],Min(u.f[i][j][0]+i+(w-i-j-k>=3),4));
if(w>=2)
for(register int k=0;k<3&&i+j+k<=w-2;++k)
v.f[j][k][1]=Max(v.f[j][k][1],Min(u.f[i][j][0]+i,4));
}
if(~u.f[i][j][1])
for(register int k=0;k<3&&i+j+k<=w;++k)
v.f[j][k][1]=Max(v.f[j][k][1],Min(u.f[i][j][1]+i+(w-i-j-k>=3),4));
}
return v;
}
inline void build(register node u)
{
if(u.hu())
return;
if(ma.find(u)!=ma.end())
return;
ma[u]=++tot;
S[tot]=u;
for(register int i=0;i<=4;++i)
build(trans(u,i));
}
int n,s[N],ans;
int fac[N],inv[N],invf[N],tr[2100][5],f[2][2100][N];
inline int C(register int n,register int m)
{
return 1ll*fac[n]*invf[m]%mod*invf[n-m]%mod;
}
int main()
{
rt.init();
build(rt);
invf[0]=inv[0]=inv[1]=fac[0]=1;
for(register int i=1;i<N;++i)
fac[i]=1ll*fac[i-1]*i%mod;
for(register int i=2;i<N;++i)
inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
for(register int i=1;i<N;++i)
invf[i]=1ll*invf[i-1]*inv[i]%mod;
n=read();
for(register int i=1;i<=13;++i)
++s[read()],read();
for(register int i=1;i<=tot;++i)
for(register int j=0;j<=4;++j)
tr[i][j]=ma[trans(S[i],j)];
f[0][1][0]=1;
for(register int i=1,sum=0;i<=n;++i)
{
int now=i&1,pre=now^1;
memset(f[now],0,sizeof(f[now]));
for(register int j=1;j<=tot;++j)
for(register int k=s[i];k<=4;++k)
{
if(!tr[j][k])
continue;
int w=1ll*C(4-s[i],k-s[i])*fac[k-s[i]]%mod;
for(register int l=0;l<=4*n-k;++l)
{
if(!f[pre][j][l])
continue;
f[now][tr[j][k]][l+k]=(0ll+f[now][tr[j][k]][l+k]+1ll*f[pre][j][l]*w%mod*C(k+l-sum-s[i],k-s[i])%mod)%mod;
}
}
sum+=s[i];
}
for(register int i=13,w=1;i<=4*n;++i)
{
int now=0;
for(register int j=1;j<=tot;++j)
now=(0ll+now+f[n&1][j][i])%mod;
ans=(0ll+ans+1ll*now*w%mod)%mod;
w=1ll*w*inv[4*n-i]%mod;
}
write(ans);
return 0;
}

【题解】Luogu P5279 [ZJOI2019]麻将的更多相关文章

  1. Luogu P5279 [ZJOI2019]麻将

    ZJOI2019神题,间接送我退役的神题233 考场上由于T2写挂去写爆搜的时候已经没多少时间了,所以就写挂了233 这里不多废话直接开始讲正解吧,我们把算法分成两部分 1.建一个"胡牌自动 ...

  2. 洛谷P5279 [ZJOI2019]麻将

    https://www.luogu.org/problemnew/show/P5279 以下为个人笔记,建议别看: 首先考虑如何判一个牌型是否含有胡的子集.先将牌型表示为一个数组num,其中num[i ...

  3. 洛谷P5279 [ZJOI2019]麻将(乱搞+概率期望)

    题面 传送门 题解 看着题解里一堆巨巨熟练地用着专业用语本萌新表示啥都看不懂啊--顺便\(orz\)余奶奶 我们先考虑给你一堆牌,如何判断能否胡牌 我们按花色大小排序,设\(dp_{0/1,i,j,k ...

  4. 洛谷 P5279 - [ZJOI2019]麻将(dp 套 dp)

    洛谷题面传送门 一道 dp 套 dp 的 immortal tea 首先考虑如何判断一套牌是否已经胡牌了,考虑 \(dp\)​​​​​.我们考虑将所有牌按权值大小从大到小排成一列,那我们设 \(dp_ ...

  5. [ZJOI2019]麻将(动态规划,自动机)

    [ZJOI2019]麻将(动态规划,自动机) 题面 洛谷 题解 先做一点小铺垫,对于一堆牌而言,我们只需要知道这\(n\)张牌分别出现的次数就行了,即我们只需要知道一个长度为\(n\)的串就可以了. ...

  6. [题解] Luogu P5446 [THUPC2018]绿绿和串串

    [题解] Luogu P5446 [THUPC2018]绿绿和串串 ·题目大意 定义一个翻转操作\(f(S_n)\),表示对于一个字符串\(S_n\), 有\(f(S)= \{S_1,S_2,..., ...

  7. 题解 洛谷 P5279 【[ZJOI2019]麻将】

    这题非常的神啊...蒟蒻来写一篇题解. Solution 首先考虑如何判定一副牌是否是 "胡" 的. 不要想着统计个几个值 \(O(1)\) 算,可以考虑复杂度大一点的. 首先先把 ...

  8. 【题解】Luogu P5327 [ZJOI2019]语言

    原题传送门 看到这种树上统计点对个数的题一般是线段树合并,这题也不出意外 先对这棵树进行树剖,对于每次普及语言,在\(x,y\)两点的线段树上的\(x,y\)两位置打\(+1\)标记,在点\(fa[l ...

  9. 【题解】Luogu P5328 [ZJOI2019]浙江省选

    原题传送门 看起来挺妙实际很暴力的一题 已知每个选手的分数都是平面上的直线 题目实际就是让我们求每条直线在整点处最大是第几大 我们考虑先对所有的直线进行半平面交(因为\(a_i\)都是正整数,所以比普 ...

随机推荐

  1. 可持久化0-1Trie树

    我跟可持久化数据结构杠上了 \(QwQ\) .三天模拟赛考了两次可持久化数据结构(主席树.可持久化0-1Trie树),woc. 目录: 个人理解 时空复杂度分析 例题及简析 一.个人理解 可持久化0- ...

  2. MYSQL避免重复插入记录的三种方法

      方案一:使用ignore关键字 如果是用主键primary或者唯一索引unique区分了记录的唯一性,避免重复插入记录可以使用: insert ignore into table_name(ema ...

  3. 【Beta】发布说明

    再次号外!Visual Pytorch第二个版本上线了! 目前的网址在这里(http://114.115.151.39/) 哦 有关上一版本的功能介绍说明请参考博客:Visual Pytorch -- ...

  4. test软件工程第三次作业

    零.前言 本次作业要求个人编写程序,截止日期2019年9月25日23:00. 请先阅读<构建之法>第一章至第三章的内容,并在下方作业里体现出阅读后的成果.特别是第2章中的效能分析及个人软件 ...

  5. 反射调用异常InvocationTargetException和代理类抛出异常

    反射调用方法,如果方法抛出异常,会被包装成InvocationTargetException. 如果反射对象被代理了,在代理类中抛出异常,不会被包装成InvocationTargetException ...

  6. git rebase 多分支操作

    - git rebase and git merge 区别 这一次彻底搞懂 Git Rebase - git在工作中正确的使用方式----git rebase篇 Git 操作假设Git目前只有一个分支 ...

  7. 试图从目录中执行 CGI、ISAPI 或其他可执行程序

    首先来看我遇到问题时的情况,直接上图!   从上图的错误提示信息可以看出,是权限不够,被拒绝访问,开始我以为是我的程序的php程序的原因,但是其他站点没事啊,就对这个站点的权限重新分配了下,给了最高权 ...

  8. spark跑YARN模式或Client模式提交任务不成功(application state: ACCEPTED)(转)

    不多说,直接上干货! 问题详情 电脑8G,目前搭建3节点的spark集群,采用YARN模式. master分配2G,slave1分配1G,slave2分配1G.(在安装虚拟机时) export SPA ...

  9. return & exit . in GO

    return结束当前函数,并返回指定值runtime.Goexit结束当前goroutine,其他的goroutine不受影响,主程序也一样继续运行os.Exit会结束当前程序,不管你三七二十一

  10. Flutter入门(二)

    * 网格布局 class HomeContent extends StatelessWidget { List<Widget> _getListData() { var tempList ...