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)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • ESCMScript(2)Module语法[通俗易懂]

    ESCMScript(2)Module语法[通俗易懂]严格模式ES6的模块自动采用严格模式,不管你有没有在模块头部加上"usestrict";。严格模式的限制如下变量必须声明后再使用函数的参数不能有同名属性,否则报错不能

    2022年7月29日
    10
  • redis查数据

    redis查数据

    2021年11月3日
    45
  • 判断三点是顺时针还是逆时针方向

    判断三点是顺时针还是逆时针方向

    2021年9月10日
    128
  • Dubbo入门_dubbo的原理

    Dubbo入门_dubbo的原理dubbo分布式系统简介发展演变RPCdubbo核心概念搭建dubbo分布式系统简介“分布式系统是若干独立计算机的集合,这些计算机对于用户来说就像单个相关系统”分布式系统(distributed system)是建立在网络之上的软件系统。随着互联网的发展,网站应用的规模不断扩大,常规的垂直应用架构已无法应对,分布式服务架构以及流动计算架构势在必行,亟需一个治理系统确保架构有条不紊的演进。发展演变单一应用架构当网站流量很小时,只需一个应用,将所有功能都部署在一起,以减少部署节点和成本。此时

    2022年8月8日
    8
  • Iocomp VC2017 – 5.12版本Crack

    Iocomp VC2017 – 5.12版本CrackIocomp工业仪表盘控件包(.net版)包括多种用来创建专业的仪表和测量、工业控制、工业监控等相关的应用程序的控件包,包括仪表盘控件,开关控件,实时曲线控件,LED灯控件等等。所有的控件均为100%托管代码,Ω578867473知道支持Microsoft/Borland/CodeGear/Embarcadero等不同的开发环境。包括三个不同的版本,终极版(ultimate),专业版(ProPack)和曲线版(PlotPack.)控件包中的所有控件都是面向对象的设计,并.

    2022年7月25日
    14
  • linux下的C语言编程(总结篇)

    linux下的C语言编程(总结篇)【声明:版权所有,欢迎转载,请勿用于商业用途。联系信箱:feixiaoxing@163.com】在Linux下面关于C语言的内容其实挺多的。不同的人关注的地方也不一样。关注系统设计的人可能更关注整个linux系统的结构;设计驱动的人可能更关注linux驱动的配置和实现;而我在这里所关注的只是linux应用层方面的内容,属于最基础的内容,当然也是最重要的内容。实际上对应于………

    2022年7月26日
    7

发表回复

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

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