3042b什么意思_XC3042

3042b什么意思_XC3042Loj #3042. 「ZJOI2019」麻将

大家好,又见面了,我是你们的朋友全栈君。

Loj #3042. 「ZJOI2019」麻将

题目描述

九条可怜是一个热爱打麻将的女孩子。因此她出了一道和麻将相关的题目,希望这题不会让你对麻将的热爱消失殆尽。

1.png

今天,可怜想要打麻将,但是她的朋友们都去下自走棋了,因此可怜只能自己一个人打。可怜找了一套特殊的麻将,它有 \(n(n \ge 5)\) 种不同的牌,大小分别为 \(1\)\(n\),每种牌都有 \(4\) 张。

定义面子为三张大小相同或者大小相邻的麻将牌,即大小形如 \(i, i, i(1 \le i \le n)\) 或者\(i, i + 1, i + 2(1 \le i \le n − 2)\)。定义对子为两张大小相同的麻将牌,即大小形如 \(i, i(1 \le i \le n)\)

定义一个麻将牌集合 \(S\) 是胡的当且仅当它的大小为 \(14\) 且满足下面两个条件中的至少一个:

\(S\) 可以被划分成五个集合 \(S_1\)\(S_5\)。其中 \(S_1\) 为对子,\(S_2\)\(S_5\) 为面子。

\(S\) 可以被划分成七个集合 \(S_1\)\(S_7\),它们都是对子,且对应的大小两两不同

举例来说,下列集合都是胡的(这儿只标记了大小):

\(\{1, 1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9\}\)

\(\{1, 1, 2, 2, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8\}\)

\(\{1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7\}\)

而下列集合都不是胡的:

\(\{1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9\}\)

\(\{1, 1, 1, 1, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8\}\)

\(\{1, 1, 1, 2, 3, 4, 5, 6, 7, 8, 9, 9, 9, 11\}\)

可怜先摸出了 \(13\) 张牌,并把剩下的 \(4n − 13\) 张牌随机打乱。打乱是等概率随机的,即所有 \((4n − 13)!\) 种排列都等概率出现。

对于一个排列 \(P\),可怜定义 \(S_i\) 为可怜事先摸出的 \(13\) 张牌加上 \(P\) 中的前 \(i\) 张牌构成的集合,定义 \(P\) 的权值为最小的 \(i\) 满足 \(S_i\) 存在一个子集是胡的。如果你对麻将比较熟悉,不难发现 \(P\) 的权值就是理论上的最早胡牌巡目数。注意到 \(n \ge 5\) 的时候,\(S_{4n−13}\) 总是存在胡的子集的,因此 \(P\) 的权值是良定义的。

现在可怜想要训练自己的牌效,因此她希望你能先计算出 \(P\) 的权值的期望是多少。

\(\\\)

神仙的\(DP\)\(DP\)题。

首先想如何判断一个局面是胡的。对于第一种胡牌方式,我们用\(DP\)来维护。设\(f_{i,j,k,0/1}\)表示是考虑了前\(i\)种麻将,以\(i-1\)开头的面子有\(j\)个,以\(i\)开头的面子有\(k\)个,是否有对子的最大面子数。注意这里以\(i-1\)开头以及以\(i\)开头的面子都是还没有生效的,要放了大小为\(i+1\)的麻将后才能判断。转移的时候就枚举第\(i\)张牌放入了\(x\)个,枚举几种情况就好了。

对于第二种胡牌方式,直接记\(cnt\)表示不同的顺子个数就行了。

显然\(cnt\)不能达到\(7\)\(f_{i,j,k,1}\)的最大值不能达到\(4\)。于是我们就暴力将\(cnt\)以及\(f\)数组作为状态。如果\(f\)超过\(4\),就存成\(4\)\(cnt\)同理,以减小状态量。可以算出合法状态最多\(2091\)个。

然后就是\(DP\)计数了。设\(F_{i,j,S}\)表示考虑了前\(i\)种麻将,一共摸了\(j\)张牌,\(DP\)状态为\(S\)还未胡牌的概率。转移的时候枚举额外摸了多少张\(i\)麻将(除去底牌)。

我们的定义是还未胡牌而不是已经胡牌的原因是我们枚举的麻将顺序是编号,不是模到这张牌的时间,所以对于一个胡牌的局面,我们不知道他到底是什么时候胡的。

利用一个经典的期望转概率的公式就可以算出答案了:
\[ E=\sum i*P(x=i)\\ =\sum P(x\geq i) \]
代码:

#include<bits/stdc++.h>
#define ll long long
#define N 105
#define M 405

using namespace std;
inline int Get() {int x=0,f=1;char ch=getchar();while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}while('0'<=ch&&ch<='9') {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}return x*f;}

const ll mod=998244353;
ll ksm(ll t,ll x) {
    ll ans=1;
    for(;x;x>>=1,t=t*t%mod)
        if(x&1) ans=ans*t%mod;
    return ans;
}
ll fac[M],ifac[M];
ll C(int n,int m) {return fac[n]*ifac[m]%mod*ifac[n-m]%mod;}
struct info {
    int f[3][3][2];
    int cnt;
    info() {memset(f,-1,sizeof(f));f[0][0][0]=cnt=0;}
    bool operator <(const info &a)const {
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                for(int k=0;k<2;k++)
                    if(f[i][j][k]!=a.f[i][j][k]) return f[i][j][k]<a.f[i][j][k];
        return cnt<a.cnt;
    }
    bool chk() {
        if(cnt>=7) return 0;
        for(int i=0;i<3;i++)
            for(int j=0;j<3;j++)
                if(f[i][j][1]>=4) return 0;
        return 1;
    }
    info trans(int x) {
        info tem;
        tem.cnt=cnt+(x>=2);
        for(int i=0;i<3;i++) {
            for(int j=0;j<3;j++) {
                for(int k=0;k<2;k++) {
                    if(f[i][j][k]==-1) continue ;
                    for(int t=0;t<3&&i+j+t<=x;t++) {
                        tem.f[j][t][k]=max(tem.f[j][t][k],f[i][j][k]+i+(x-i-j-t>=3));
                    }
                    if(!k) {
                        for(int t=0;t<3&&i+j+t<=x-2;t++) {
                            tem.f[j][t][1]=max(tem.f[j][t][1],f[i][j][k]+i);
                        }
                    }
                }
            }
        }
        for(int k=0;k<2;k++)
            for(int i=0;i<3;i++)
                for(int j=0;j<3;j++)
                    tem.f[i][j][k]=min(tem.f[i][j][k],4);
        return tem;
    }
};

int n;
map<info,int>id;
info mj[4005];
int tot;
int Had[N];
info tem;
int trans[4005][5];
void dfs(info now) {
    if(!now.chk()) return ;
    id[now]=++tot;
    mj[tot]=now;
    for(int i=0;i<=4;i++) {
        info tem=now.trans(i);
        if(id.find(tem)==id.end()) dfs(tem);
        trans[id[now]][i]=id[tem];
    }
}

ll f[N][M][2100];
int main() {
    fac[0]=1;
    for(int i=1;i<=400;i++) fac[i]=fac[i-1]*i%mod;
    ifac[400]=ksm(fac[400],mod-2);
    for(int i=399;i>=0;i--) ifac[i]=ifac[i+1]*(i+1)%mod;
    info x;
    dfs(x);
    n=Get();
    
    for(int i=1;i<=13;i++) {
        int w=Get(),t=Get();
        Had[w]++;
    }
    
    f[0][0][1]=1;
    for(int i=0;i<n;i++) {
        for(int j=0;j<=i*4;j++) {
            for(int k=1;k<=tot;k++) {
                if(!f[i][j][k]) continue ;
                for(int t=Had[i+1];t<=4;t++) {
                    if(trans[k][t]) (f[i+1][j+t-Had[i+1]][trans[k][t]]+=f[i][j][k]*C(4-Had[i+1],t-Had[i+1])%mod*C(j+t-Had[i+1],t-Had[i+1])%mod*fac[t-Had[i+1]])%=mod;
                }
            }
        }
    }
    
    ll ans=0;
    for(int i=0;i<=4*n-13;i++) {
        for(int j=1;j<=tot;j++) {
            (ans+=f[n][i][j]*ifac[4*n-13]%mod*fac[4*n-13-i])%=mod;
        }
    }
    cout<<ans;
    
    return 0;
}

转载于:https://www.cnblogs.com/hchhch233/p/10821757.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/106837.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • C++实现矩阵类(附代码和功能)

    C++实现矩阵类(附代码和功能)本文由两部分组成,第一部分介绍一个在win10系统上运行的exe程序,第二部分介绍通过C++实现矩阵运算的方法(功能会更强大,但不如exe文件操作方便)。用户界面如下,能够实现矩阵的加、减、乘、除运算,以及矩阵的转置,求逆,求行列式的值等。读者可以在下载该程序,直接在自己的电脑上运行。下载地址:https://download.csdn.net/do…

    2022年6月28日
    27
  • Spring Boot实现MyBatis分页查询[通俗易懂]

    Spring Boot实现MyBatis分页查询[通俗易懂]综合概述想必大家都有过这样的体验,在使用Mybatis时,最头痛的就是写分页了,需要先写一个查询count的select语句,然后再写一个真正分页查询的语句,当查询条件多了之后,会发现真的不想花双倍的时间写count和select,幸好我们有pagehelper分页插件,pagehelper是一个强大实用的MyBatis分页插件,可以帮助我们快速的实现MyBatis分页功能,而且pagehelper有个优点是,分页和Mapper.xml完全解耦,并以插件的形式实现,对Mybatis执行的.

    2022年5月5日
    68
  • python自动炒股软件下载_python自动股票交易软件

    python自动炒股软件下载_python自动股票交易软件获取数据是数据分析中必不可少的一部分,而网络爬虫是是获取数据的一个重要渠道之一。鉴于此,我拾起了Python这把利器,开启了网络爬虫之路。本篇使用的版本为python3.5,意在抓取证券之星上当天所有A股数据。程序主要分为三个部分:网页源码的获取、所需内容的提取、所得结果的整理。一、网页源码的获取很多人喜欢用python爬虫的原因之一就是它容易上手。只需以下几行代码既可抓取大部分网页的源码。imp…

    2022年6月19日
    41
  • 使用html css实现180箭头旋转,纯CSS实现箭头旋转「建议收藏」

    使用html css实现180箭头旋转,纯CSS实现箭头旋转「建议收藏」无标题文档b{position:absolute;right:10px;top:7px;width:0;height:0;border-width:4px4px;border-style:solid;border-color:#666#f5f5f5#f5f5f5;font-size:0;line-height:0;-webkit-transition:-webkit-transform.2…

    2025年6月2日
    1
  • 如何零基础开始自学Python编程「建议收藏」

    如何零基础开始自学Python编程「建议收藏」转载——原作者:赛门喵链接:https://www.zhihu.com/question/29138020/answer/1411702420.明确目标我是真正零基础开始学Python的,从一

    2022年7月5日
    22
  • matlab中find函数用法[通俗易懂]

    matlab中find函数用法[通俗易懂]1.返回素有非零元素的位置例如:注:竖着数!!2.条件:find(A==1)例如:返回的仍然是位置!3.返回前N个非零元素的位置,find(A,X)例如:4.返回最后一个非零值的位置find(A,1,‘last’)例如:5.返回最后一个非零值的行列位置或者A中非零元素位置例如:6.[a,b,v]=find(A),找出A中非零元素所在的行和列,分别存储在a和b中,…

    2022年7月17日
    13

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号