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)
上一篇 2022年4月22日 上午7:20
下一篇 2022年4月22日 上午7:20


相关推荐

  • ms-settings:personalization-background解决办法

    ms-settings:personalization-background解决办法前言 在今天整理电脑和卸载一些没用的软件的时候发生了一个错误 导致电脑不能正常运行 键盘和鼠标都不管用 桌面上的所有图标也都不见了 但是在键盘上调任务管理器能调出来 查了很多办法说最好的办法就是重装系统 可是想了想重装系统太费事了 而且有些数据没备份怕丢失 所以查各种方法 最后给解决了 现在分享给大家 一 问题原因 最开始不知道问题是什么 通过查英文单词 说是 设置个性化背景 想了想

    2026年3月17日
    3
  • spss聚类分析的简单例题_聚类分析的简单例题

    spss聚类分析的简单例题_聚类分析的简单例题一、什么是聚类分析聚类分析指将物理或抽象对象的集合分组为由类似的对象组成的多个类的分析过程。它是一种重要的人类行为。聚类分析的目标就是在相似的基础上收集数据来分类。聚类源于很多领域,包括数学,计算机科学,统计学,生物学和经济学。在不同的应用领域,很多聚类技术都得到了发展,这些技术方法被用作描述数据,衡量不同数据源间的相似性,以及把数据源分类到不同的簇中。——《百度百科–聚类分析》二、基本步…

    2022年8月31日
    6
  • Linux常用命令面试题(linux面试题必会题目)

    Linux常用命令因为热爱,所以拼搏。–RuiDer常用指令ls  显示文件或目录-l列出文件详细信息l(list)-a列出当前目录下所有文件及目录,包括隐藏的a(all)mkdir创建目录-p创建目录,若…

    2022年4月12日
    50
  • C#多线程

    C#多线程C#多线程简单示例Thread类构造函数可以传入一个委托,作为线程调用的方法。1usingSystem;2usingSystem.Threading;34namespaceTes

    2022年7月2日
    34
  • 2.海龟作图—-用Python绘图[通俗易懂]

    2.海龟作图—-用Python绘图[通俗易懂]第一个海龟程序 #SquareSpiral1.py画一个正方形螺旋线importturtlet=turtle.Pen()forxinrange(1,100):#1<=x<100t.forward(x)t.left(90) 旋转的海龟 #SquareSpiral2.pyimportturtlet=turtle.Pen()forxinrange(100):t.forward(x)t.le…

    2022年6月28日
    30
  • win10系统IIS服务器配置详细教程,win10系统配置iis的操作方法

    win10系统IIS服务器配置详细教程,win10系统配置iis的操作方法很多小伙伴都遇到过对 win10 系统配置 iis 的设置方法 想必大家都遇到过需要对 win10 系统配置 iis 进行设置的情况吧 那么应该怎么设置 win10 系统配置 iis 的操作方法非常简单 只需要 一 计算机 控制面板 程序 二 打开或关闭 Windows 功能 这样的步骤就可以了 下面小编带领大家看看 win10 系统配置 iis 具体的操作方法 IIS 安装具体过程步骤如下一 计算机 控制面板 程序 二 打开或

    2026年3月17日
    2

发表回复

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

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