「ZJOI2019」麻将
传送门
Solution
对于条件一:记录一个\(cnt\)表示牌个数\(≥2\)的个数
设\(dp_{i,0/1,j,k}\)表示考虑了\(1...i\),当前是否有对子,以\(i-1\),\(i\)开始的顺子数为\(j\),\(k\)个,的最大面子数
其中\(dp_i\)是一个大小为\(18\)的状态,我们通过搜索可以发现这样的状态很少
不胡的状态有\(2091\)个,可以直接开一个\(map\)来记录,这里要记得重载小于号
将期望看成,如果摸了\(i(i≥13)\)张牌,如果仍然不胡则贡献\(1\)
答案需要求出有\(i\)张牌时仍然不胡的方案数,并乘一个排列数\((4n-i)!\)
仍然考虑dp,设\(f_{i,j,k}\)表示考虑\(1...i\),当前状态为\(j\),一共选了\(k\)张牌的方案数
转移时枚举\(i+1\)面值选多少张即可
总复杂度\(O(n^2S)\),\(S\)表示状态数
Code
#include<bits/stdc++.h>
using namespace std;
#define reg register
inline int read()
{
int x=0,f=1;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;
}
const int P=998244353,C[5][5]={{1},{1,1},{1,2,1},{1,3,3,1},{1,4,6,4,1}};
int Mul(int x,int y){return (1ll*x*y)%P;}
int Add(int x,int y){return (x+y)%P;}
int n,w[15],t[105];
void rw(int &x,int y){if(min(y,4)>x)x=y;}
struct State
{
int f[18],cnt;
State(){memset(f,-1,sizeof f);f[0]=cnt=0;}
bool operator <(const State&o)const
{
if(cnt!=o.cnt) return (cnt<o.cnt);
for(int i=0;i<18;++i)
if(f[i]!=o.f[i]) return (f[i]<o.f[i]);
return false;
}
bool HU(){return cnt>=7||f[9]>=4;}
friend State Trans(State a,int b)
{
register int i,j,k;State c;c.cnt=a.cnt+(b>=2);
for(i=0;i<3;++i)for(j=0;j<3;++j)for(k=0;k<3&&i+j+k<=b;++k)
{
if(~a.f[i*3+j]) rw(c.f[j*3+k],a.f[i*3+j]+i+(b-i-j-k)/3);
if(~a.f[i*3+j+9])rw(c.f[9+j*3+k],a.f[9+i*3+j]+i+(b-i-j-k)/3);
if(i+j+k+2<=b&&~a.f[i*3+j]) rw(c.f[9+j*3+k],a.f[i*3+j]+i);
}
return c;
}
}st[2100];int tot;int tr[2100][5];
std::map<State,int> mp;
int dfs(State cur)
{
if(cur.HU()) return 0;
if(mp.find(cur)!=mp.end()) return mp[cur];
st[mp[cur]=++tot]=cur;int now=tot;
for(int i=0;i<=4;++i) tr[now][i]=dfs(Trans(cur,i));
return now;
}
int f[2][2100][405],fac[450],inv[450],ans;
int main()
{
dfs(State());
register int sum,i,j,k,l;
for(inv[0]=inv[1]=fac[0]=fac[1]=1,i=2;i<=420;++i)
fac[i]=Mul(fac[i-1],i),inv[i]=Mul((P-P/i),inv[P%i]);
for(i=2;i<=420;++i) inv[i]=Mul(inv[i],inv[i-1]);
n=read();
for(i=1;i<=13;++i) w[i]=read(),read(),++t[w[i]];
f[0][1][0]=1;
for(sum=0,i=1;i<=n;sum+=t[i],++i)
{
memset(f[i&1],0,sizeof f[i&1]);
for(j=1;j<=tot;++j)for(k=sum;k<=(i-1)<<2;++k)if(f[(i&1)^1][j][k])for(l=t[i];l<=4;++l)if(tr[j][l])
{
int nxt=tr[j][l];
f[i&1][nxt][k+l]=Add(f[i&1][nxt][k+l],
Mul(f[(i&1)^1][j][k],Mul(C[4-t[i]][l-t[i]],Mul(inv[k-sum],fac[k+l-sum-t[i]]))));
}
}
ans=0;
for(i=0;i<=(n<<2);ans=Add(ans,Mul(l,fac[(n<<2)-i])),++i)
for(l=0,j=1;j<=tot;l=Add(l,f[n&1][j][i]),++j);
printf("%d\n",Mul(ans,inv[(n<<2)-13]));
return 0;
}
Blog来自PaperCloud,未经允许,请勿转载,TKS!
「ZJOI2019」麻将的更多相关文章
- Loj #3042. 「ZJOI2019」麻将
Loj #3042. 「ZJOI2019」麻将 题目描述 九条可怜是一个热爱打麻将的女孩子.因此她出了一道和麻将相关的题目,希望这题不会让你对麻将的热爱消失殆尽. 今天,可怜想要打麻将,但是她的朋友们 ...
- 【LOJ】#3042. 「ZJOI2019」麻将
LOJ#3042. 「ZJOI2019」麻将 如何判定一个集合牌有没有胡的子集是不是胡的 就用一个\(dp[j][k][0/1]\)表示有j个连续两个的串,有k个连续1个串,有没有对子,再记一下这个集 ...
- 「ZJOI2019」&「十二省联考 2019」题解索引
「ZJOI2019」&「十二省联考 2019」题解索引 「ZJOI2019」 「ZJOI2019」线段树 「ZJOI2019」Minimax 搜索 「十二省联考 2019」 「十二省联考 20 ...
- LOJ3044. 「ZJOI2019」Minimax 搜索
LOJ3044. 「ZJOI2019」Minimax 搜索 https://loj.ac/problem/3044 分析: 假设\(w(1)=W\),那么使得这个值变化只会有两三种可能,比\(W\)小 ...
- Loj #3044. 「ZJOI2019」Minimax 搜索
Loj #3044. 「ZJOI2019」Minimax 搜索 题目描述 九条可怜是一个喜欢玩游戏的女孩子.为了增强自己的游戏水平,她想要用理论的武器武装自己.这道题和著名的 Minimax 搜索有关 ...
- Loj #3045. 「ZJOI2019」开关
Loj #3045. 「ZJOI2019」开关 题目描述 九条可怜是一个贪玩的女孩子. 这天,她和她的好朋友法海哥哥去玩密室逃脱.在他们面前的是 \(n\) 个开关,开始每个开关都是关闭的状态.要通过 ...
- 【LOJ】#3046. 「ZJOI2019」语言
LOJ#3046. 「ZJOI2019」语言 先orz zsy吧 有一个\(n\log^3n\)的做法是把树链剖分后,形成logn个区间,这些区间两两搭配可以获得一个矩形,求矩形面积并 然后就是对于一 ...
- 【LOJ】#3044. 「ZJOI2019」Minimax 搜索
LOJ#3044. 「ZJOI2019」Minimax 搜索 一个菜鸡的50pts暴力 设\(dp[u][j]\)表示\(u\)用\(j\)次操作能使得\(u\)的大小改变的方案数 设每个点的初始答案 ...
- 【LOJ】#3043. 「ZJOI2019」线段树
LOJ#3043. 「ZJOI2019」线段树 计数转期望的一道好题-- 每个点设两个变量\(p,q\)表示这个点有\(p\)的概率有标记,有\(q\)的概率到祖先的路径上有个标记 被覆盖的点$0.5 ...
随机推荐
- Date类的相关方法记录
1.Date类中的时间单位是毫秒,System.currentTimeMills()方法就是获取当前时间到1970年1月1日0时0分0秒(西方时间)的毫秒数. public class Test6 { ...
- python抓取贝壳房源信息
分析了贝壳的房源信息数据,发现地址链接的参数传递是有规律的 https://tj.ke.com/chengjiao/a3l4/ a3 实际表示的 l4 表示的是 然后 将复合条件拼成一个字符串,带过去 ...
- kali之使用sqlmap进行sql注入
sqlmap简介 sqlmap支持五种不同的注入模式: 1.基于布尔的盲注,即可以根据返回页面判断条件真假的注入. 2.基于时间的盲注,即不能根据页面返回内容判断任何信息,用条件语句查看时间延迟语句是 ...
- 基于webpack的前端工程化开发解决方案探索(三):webpack-dev-server
前两篇中我们使用webpack完成了静态资源(css/js/img)等自动写入HTML模板中,同时还可以为静态资源添加hash版本号,既满足了我们对于静态资源的打包要求,同时又无需开发人员介入打包过程 ...
- Linux E667 同步失败
在使用Vim编辑/proc目录下的文件后,保存,显示"E667 同步失败" 原因 因为proc这个目录是一个虚拟文件系统,它放置的数据都是在内存中,本身不占有磁盘空间,所以使用Vi ...
- 使用Prometheus针对自己的服务器采集自定义的参数
用一个简单的例子来说明. 我用express和http搭了一个最简单的服务器,监听在8081端口上. 在metrics endpoint上,我会打印出这个服务器从启动至今,服务了多少次请求.这里我只是 ...
- 部署GitLab时, 问题
1. 开启防火墙可能会对 nginx 造成影响. 2. 安装 gitlab 会自带一个 nginx, 启动后会对 现有的nginx 造成影响, 解决方案 参考 连接 1
- GDI显示图像时设定窗口大小为图像大小
先前已经能基于GDI显示png图像,但是窗口大小和图像尺寸并不一致.注意到opencv中的imshow的窗口和图像尺寸一致,这里进行设置. 原理 CreateWindow阶段并不能确定窗口大小,但是在 ...
- 解决windows下合上、掀开笔记本盖子后屏幕黑屏的问题
我在macbook上安装了windows10,但是由于驱动问题,虽然我设置的是关闭盖子仅息屏,但是在关闭盖子后一段时间,再掀开,屏幕就怎么样都唤不醒了. 我找到一个方法,虽然治标不治本,但是起码能解决 ...
- Eureka 中服务下线的几种方式
原文:https://blog.csdn.net/qq_15071263/article/details/85276486#1_6 Eureka 中服务下线的几种方式1.直接停掉服务根据默认的策略,如 ...