首先只需要考虑每种牌出现的张数即可,然后判断一副牌是否能胡,可以DP一下,令f[i][j][k][0/1]表示到了第i位,用j次i-1,i,i+1和k次i,i+1,i+2,是否出现对子然后最大的面子数量,j,k∈[0,2],转移也很容易。这样暴力枚举可以获得50pts的“好”成绩。

然后可以丢掉第一维,只考虑18个状态最大可能对子数,强制f值<=4,最大对子数<=7,发现状态不到5000种。

然后把所有状态预处理,丢掉重复的状态,把有用状态建在自动机上。所以仅需从头到尾插入一种状态即可知道是否胡牌。

然后可以DP了,f[i][j][k]表示DP到第i种牌,状态在自动机j位置,抽了k张没胡的方案,直接转移即可。

#include<bits/stdc++.h>
using namespace std;
const int N=,mod=;
int n,tot,ans,c[][],fac[N],inv[N],has[N],f[][N][],ch[N][];
struct node{
int f[][][],cnt;
node(){memset(f,-,sizeof f),f[][][]=cnt=;}
bool operator<(const node&x)const
{
for(int i=;i<;i++)
for(int j=;j<;j++)
for(int k=;k<;k++)
if(f[i][j][k]!=x.f[i][j][k])return f[i][j][k]<x.f[i][j][k];
return cnt<x.cnt;
}
}st[N];
void add(int&a,long long b){a=(a+b)%mod;}
map<node,int>S;
node trans(node u,int x)
{
node ret;
ret.cnt=min(u.cnt+(x>=),);
for(int a=;a<;a++)
for(int b=;a+b<;b++)
for(int i=;i<;i++)
for(int j=;j<;j++)
for(int k=;k<;k++)
if(i+j+k+b*<=x&&u.f[a][i][j]!=-)
ret.f[a+b][j][k]=max(ret.f[a+b][j][k],min(u.f[a][i][j]+i+(x-i-j-k-b*)/,));
return ret;
}
int dfs(node u)
{
if(S.count(u))return S[u];
if(u.cnt==)return ;
for(int i=;i<;i++)for(int j=;j<;j++)if(u.f[][i][j]==)return ;
st[++tot]=u,S[u]=tot;
int pos=tot;
for(int i=;i<=;i++)ch[pos][i]=dfs(trans(u,i));
return pos;
}
int main()
{
scanf("%d",&n);
for(int i=,x;i<=;i++)scanf("%d%*d",&x),has[x]++;
for(int i=;i<=;i++)
{
c[i][]=;
for(int j=;j<=i;j++)c[i][j]=c[i-][j-]+c[i-][j];
}
fac[]=inv[]=inv[]=;for(int i=;i<=*n;i++)inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
for(int i=;i<=*n;i++)fac[i]=1ll*fac[i-]*i%mod,inv[i]=1ll*inv[i-]*inv[i]%mod;
dfs(node());
f[][][]=;
for(int i=;i<=n;i++)
{
memset(f[i&],,sizeof f[i&]);
for(int j=;j<=tot;j++)
for(int k=has[i];k<=;k++)
if(ch[j][k])
for(int t=;t<=(i-)*;t++)
add(f[i&][ch[j][k]][k+t],1ll*f[i-&][j][t]*c[-has[i]][k-has[i]]);
}
for(int i=,sum;i<=n*-;i++)
{
sum=;
for(int j=;j<=tot;j++)add(sum,f[n&][j][i+]);
add(ans,1ll*sum*fac[i]%mod*fac[*n--i]);
}
ans=(1ll*ans*inv[*n-]+)%mod;
printf("%d",ans);
}

[ZJOI2019]麻将(DP+有限状态自动机)的更多相关文章

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

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

  2. 【Codeforces 506E】Mr.Kitayuta’s Gift&&【BZOJ 4214】黄昏下的礼物 dp转有限状态自动机+矩阵乘法优化

    神题……胡乱讲述一下思维过程……首先,读懂题.然后,转化问题为构造一个长度为|T|+n的字符串,使其内含有T这个子序列.之后,想到一个简单的dp.由于是回文串,我们就增量构造半个回文串,设f(i,j, ...

  3. [ZJOI2019]麻将

    这是一道麻将自动机的模板题(雾 其实这是一道dp套dp借助自动机实现的麻将好题! 首先把期望转化一下,拆成sigema p(x>i) 现在要计算i张牌不胡的概率,也就等价于计算i张牌不胡的方案数 ...

  4. 用C语言实现有限状态自动机FSM

    摘要:状态机模式是一种行为模式,在<设计模式>这本书中对其有详细的描述,通过多态实现不同状态的调转行为的确是一种很好的方法,只可惜在嵌入式环境下,有时只能写纯C代码,并且还需要考虑代码的重 ...

  5. 非确定有限状态自动机的构建(二)——将CharVal转换为NFA

    保留版权,转载注明出处:潘军彪的个人博客(http://blog.csdn.net/panjunbiao/article/details/9378933) 将上下文无关文法读入内存之后,可以将它转换成 ...

  6. 非确定有限状态自动机的构建(一)——NFA的定义和实现

    保留版权,转载需注明出处(http://blog.csdn.net/panjunbiao). 非确定有限状态自动机(Nondeterministic Finite Automata,NFA)由以下元素 ...

  7. DFA确定有限状态自动机

    DFA 在计算理论中,确定有限状态自动机或确定有限自动机(英语:deterministic finite automaton, DFA)是一个能实现状态转移的自动机.对于一个给定的属于该自动机的状态和 ...

  8. K:有限状态自动机

      有限状态自动机是一种特殊的状态机.它表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.有限状态自动机分为两种,一种是 确定有限状态自动机(DFA) ,一种是 非确定有限状态自动机(NF ...

  9. 咕咕(数位dp+AC自动机)

    咕咕(数位dp+AC自动机) 若一个字符串的字符集合是0~m-1,那么称它为m进制字符串.给出n个m进制字符串\(s_i\),每个字符串的权值为\(v_i\).对于另一个m进制字符串\(S\),设\( ...

随机推荐

  1. Shiro密码处理

    散列算法一般用于生成数据的摘要信息,是一种不可逆的算法,一般适合存储密码之类的数据,常见的散列算法如 MD5.SHA等.一般进行散列时最好提供一个 salt(盐),比如加密密码"admin& ...

  2. docker搭建redis主从集群和sentinel哨兵集群,springboot客户端连接

    花了两天搭建redis主从集群和sentinel哨兵集群,讲一下springboot客户端连接测试情况 redis主从集群 从网上查看说是有两种方式:一种是指定配置文件,一种是不指定配置文件 引用地址 ...

  3. (递归)P1025 数的划分

    题解: #include<iostream>using namespace std;int ret=0,m_n;void p(int n,double k,int j){ if(k==1) ...

  4. tensorflow笔记2(北大网课实战)

    1.正则化缓解过拟合 正则化在损失函数中引入模型复杂度指标,利用给w加权值,弱化了训练数据的噪声 一般不会正则化b. 2.matplotlib.pyplot 3.搭建模块化的神经网络八股: 前向传播就 ...

  5. CTF - bugku-分析

    1.flag被盗 下载链接是.pcang文件 用wireshark打开 像这种流量分析题目,就要用Wireshark自带的搜索功能找尝试查找一些关键词(比如key.flag.shell.pass等) ...

  6. 通过Android的API对Sqlite数据库进行操作

    一.增删改查 增 改 查 删 这是删除之前 删除三条 Dao.java package com.example.databasedemo; import android.content.Content ...

  7. multi-task learning

    多任务学习, CTR, CVR 任务同时训练, 同时输出概率.

  8. Jetson TX2入门学习之Ubuntu默认密码

    在使用TX2开发板时进行软件更新时需要身份验证,TX2默认有两个登录身份,一个是ubuntu 一个是nvidia 登录其中的哪一个都可以更新   两个身份的密码和登录名是一样的用户:ubuntu 密码 ...

  9. 如何解决Tomcat端口号被占用

    在eclipse中配置好tomcat服务器后,启动时提示错误如下图 提示端口被占用. 第一种方法: 结束占用端口的进程 第一步:netstat -aon|findstr "端口号" ...

  10. 收藏基本Java项目开发的书

    一.Java项目开发全程实录 第1章 进销存管理系统(Swing+SQL Server2000实现) 第2章企业内部通信系统(Swing+JavaDB实现) 第3章 企业人事管理系统( Swing+H ...