[ZJOI2019]麻将(DP+有限状态自动机)
首先只需要考虑每种牌出现的张数即可,然后判断一副牌是否能胡,可以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+有限状态自动机)的更多相关文章
- [ZJOI2019]麻将(动态规划,自动机)
[ZJOI2019]麻将(动态规划,自动机) 题面 洛谷 题解 先做一点小铺垫,对于一堆牌而言,我们只需要知道这\(n\)张牌分别出现的次数就行了,即我们只需要知道一个长度为\(n\)的串就可以了. ...
- 【Codeforces 506E】Mr.Kitayuta’s Gift&&【BZOJ 4214】黄昏下的礼物 dp转有限状态自动机+矩阵乘法优化
神题……胡乱讲述一下思维过程……首先,读懂题.然后,转化问题为构造一个长度为|T|+n的字符串,使其内含有T这个子序列.之后,想到一个简单的dp.由于是回文串,我们就增量构造半个回文串,设f(i,j, ...
- [ZJOI2019]麻将
这是一道麻将自动机的模板题(雾 其实这是一道dp套dp借助自动机实现的麻将好题! 首先把期望转化一下,拆成sigema p(x>i) 现在要计算i张牌不胡的概率,也就等价于计算i张牌不胡的方案数 ...
- 用C语言实现有限状态自动机FSM
摘要:状态机模式是一种行为模式,在<设计模式>这本书中对其有详细的描述,通过多态实现不同状态的调转行为的确是一种很好的方法,只可惜在嵌入式环境下,有时只能写纯C代码,并且还需要考虑代码的重 ...
- 非确定有限状态自动机的构建(二)——将CharVal转换为NFA
保留版权,转载注明出处:潘军彪的个人博客(http://blog.csdn.net/panjunbiao/article/details/9378933) 将上下文无关文法读入内存之后,可以将它转换成 ...
- 非确定有限状态自动机的构建(一)——NFA的定义和实现
保留版权,转载需注明出处(http://blog.csdn.net/panjunbiao). 非确定有限状态自动机(Nondeterministic Finite Automata,NFA)由以下元素 ...
- DFA确定有限状态自动机
DFA 在计算理论中,确定有限状态自动机或确定有限自动机(英语:deterministic finite automaton, DFA)是一个能实现状态转移的自动机.对于一个给定的属于该自动机的状态和 ...
- K:有限状态自动机
有限状态自动机是一种特殊的状态机.它表示有限个状态以及在这些状态之间的转移和动作等行为的数学模型.有限状态自动机分为两种,一种是 确定有限状态自动机(DFA) ,一种是 非确定有限状态自动机(NF ...
- 咕咕(数位dp+AC自动机)
咕咕(数位dp+AC自动机) 若一个字符串的字符集合是0~m-1,那么称它为m进制字符串.给出n个m进制字符串\(s_i\),每个字符串的权值为\(v_i\).对于另一个m进制字符串\(S\),设\( ...
随机推荐
- iOS 多线程 GCD part3:API
https://www.jianshu.com/p/072111f5889d 2017.03.05 22:54* 字数 1667 阅读 88评论 0喜欢 1 0. 预备知识 GCD对时间的描述有些新奇 ...
- java伪代码 (第一章)
在<大道至简>第一章中,周爱民先生引用一则<愚公移山>的寓言,引出了编程的根本:顺序.选择.循环.汤问篇中所述的愚公移山这一事件,我们看到了原始需求的产生---“惩山北之塞,出 ...
- DispatcherServlet继承体系
GenericServlet implements Servlet, ServletConfig, java.io.Serializable | HttpServlet ...
- 第四章:Schema与数据类型优化
1. 选择优化的数据类型 选择数据类型的原则 更小的通常更好:选择可以正确存储数据的最小数据类型 小的数据类型消耗更少的内存.CPU;占用更少的磁盘 选用简单的数据类型:简单的数据类型通常需要更少的C ...
- MyBatis:一对多、多对一处理
多对一的处理 多对一的理解: 多个学生对应一个老师 如果对于学生这边,就是一个多对一的现象,即从学生这边关联一个老师! 数据库设计 CREATE TABLE `teacher` ( `id` INT( ...
- POJ 1273:Drainage Ditches 网络流模板题
Drainage Ditches Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 63339 Accepted: 2443 ...
- Win10下 Java环境变量配置
安装java的JDK 下载地址 此电脑->属性->高级设置 "系统变量"新建 变量名:Java_Home 变量值:D:\Program Files\Java ...
- 解决: java.io.IOException: 打开的文件过多 的问题
问题 前一阵子公司项目做了一次压力测试, 中间出现了一个问题: 在50多个并发的时候会出现 java.io.IOException: 打开的文件过多 这个异常. 但是在没有并发的时候是不会出现这个问题 ...
- Intellij IDEA破解方法
1.破解(参考网站) http://idea.lanyus.com/ 2. Intellij idea使用教程 https://github.com/tengj/IntelliJ-IDEA-Tutor ...
- SQL基础教程(第2版)第8章 SQL高级处理:8-1 窗口函数
第8章 SQL高级处理:8-1 窗口函数 ● 窗口函数可以进行排序.生成序列号等一般的聚合函数无法实现的高级操作.● 理解PARTITION BY和ORDER BY这两个关键字的含义十分重要. ■什么 ...