zoukankan      html  css  js  c++  java
  • [ZJOI2019]麻将

    题目传送门

    突然想起某个神仙教了我这道神仙题qwq那就巩固一下吧

    题意简述

    • 你有 (13) 张牌,还有 (4n-13) 张牌未摸。

    • 对于未摸的所有排列,定义 (P) 为最小的 (i) 满足 (S_i) 存在一个子集是胡的。

    • (P) 的期望。

    dp of dp

    先考虑我们最后需要什么。

    假设我们知道 (g_i) 表示摸了 (i) 张牌后不胡的方案数。

    那么我们可以将答案转化成下式。

    (dfrac{sum_{i=1}^{4n-13}g_i*i!(4n-13-i)!}{(4n-13)!}+1)

    因此,我们将答案转化为摸了 (i) 张牌不胡的方案数。

    如何判断一副牌胡没胡呢(看出来)。

    我们首先可以把相同的三个顺子视为三个刻子,这对结果没有影响。

    那我们可以认为,相同的顺子最多只有两个

    先不考虑七对子的情况。

    我们设 (f_{i,k,l,x}) 表示只考虑 ([1,i]) 之间的麻将,从 (i-1) 开始的刻子(k) 张,从 (i) 开始的刻子(l) 张,是否已经选出了一个对子(即 (x=0/1)),最多能组成多少刻子。

    那么能胡牌的条件就是 (f_n,k,l,1>3)

    七对子易特判。

    所以把 (18) 维的状态全压进dp里就好啦。

    (dp_{i,j,k,S}) 表示用了 ([1,i]),一共选了 (j) 张牌,用 (k) 种牌可以组成对子,且18维dp的状态是 (S) 的方案数。

    这个 (S) 看起来好大怎么办qaq,可以考虑提前搜出所有可能(S)

    我们可以把所有合法的状态统一为状态 (T)

    暴力发现不胡的状态**不超过 (3000) **,可以直接莽dpqwq。

    附上代码qwq。

    /*
    ***
    还要继续努力
    成为一名烤咕学家哦
    ***
    */
    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const ll Mo=998244353;
    ll m,n,p,nxt[3005][5],tot,vis[105],C[5][5],fac[505],inv[505],dp[105][405][4005];
    map<vector<ll>,ll>mp;
    template <typename T> void rd(T &x){
    	ll fl=1;x=0;char c=getchar();
    	for(;!isdigit(c);c=getchar()) if(c=='-') fl=-fl;
    	for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    	x*=fl;
    }
    void wr(ll x){
    	if(x<0) x=-x,putchar('-');
    	if(x<10) putchar(x+'0');
    	if(x>9) wr(x/10),putchar(x%10+'0');
    }
    inline void Max(ll &x,ll y){x=max(x,y);}
    ll dfs(vector<ll> nw){
    	if(mp.find(nw)!=mp.end()) return mp[nw];
    	mp[nw]=++tot;
    	ll ID=tot;
    	for(ll i=0;i<=4;++i){
    		vector<ll> temp; temp.clear();
    		for(ll j=0;j<19;++j) temp.push_back(-1);
    		temp[18]=nw[18]+(i>=2);
    		for(ll a=0;a<3;++a) for(ll b=0;b<3;++b) for(ll k=0;k<3&&a+b+k<=i;++k){
    			if(nw[a+b*3]!=-1) Max(temp[b+k*3],nw[a+b*3]+a+(i-a-b-k)/3);
    			if(nw[a+b*3+9]!=-1) Max(temp[b+k*3+9],nw[a+b*3+9]+a+(i-a-b-k)/3);
    			if(a+b+k+2<=i&&nw[a+b*3]!=-1) Max(temp[b+k*3+9],nw[a+b*3]+a); 
    		}
    		for(ll j=0;j<18;++j) temp[j]=min(temp[j],4ll);
    		if(temp[9]>=4||temp[18]>=7) nxt[ID][i]=0;
    		else nxt[ID][i]=dfs(temp);
    	}
    	return ID;
    }
    ll pre(){
    	vector<ll> nw;
    	for(ll i=0;i<18;++i) nw.push_back(-1); nw.push_back(0);
    	nw[0]=0;
    	return dfs(nw);
    }
    ll pw(ll x,ll y){
    	ll s=1;
    	while(y){
    		if(y&1) s=1ll*s*x%Mo;
    		x=1ll*x*x%Mo;y>>=1;
    	}
    	return s;
    }
    int main(){
    //	freopen(".in","r",stdin);
    //	freopen(".out","w",stdout);
    	dp[0][0][pre()]=1;
    	rd(n);
    	for(ll i=0;i<=4;++i){
    		C[i][0]=1;
    		for(ll j=1;j<=i;++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%Mo;
    	}
    	fac[0]=1;
    	for(ll i=1;i<505;++i) fac[i]=1ll*fac[i-1]*i%Mo;
    	for(ll i=0;i<505;++i) inv[i]=pw(fac[i],Mo-2); 
    	for(ll i=1,x,y;i<=13;++i){
    		rd(x),rd(y);
    		vis[x]++; 
    	}
    	ll ans=0;
    	for(ll i=1;i<=n;++i)
    		for(ll j=0;j<=4*(i-1);++j)
    			for(ll k=1;k<=tot;++k)
    				if(dp[i-1][j][k])
    					for(ll l=0;l<=4-vis[i];++l)
    						(dp[i][j+l][nxt[k][vis[i]+l]]+=1ll*dp[i-1][j][k]*C[4-vis[i]][l]%Mo)%=Mo;
    	for(ll j=0;j<=4*n-13;++j) 
    		for(ll k=1;k<=tot;++k)
    			if(dp[n][j][k]) (ans+=1ll*fac[j]*fac[4*n-13-j]%Mo*dp[n][j][k]%Mo)%=Mo;
    	wr(1ll*ans*inv[4*n-13]%Mo);puts("");
    	return 0;
    }
    

    欢迎碾压qaq。

    有没有大神带我玩awa。

  • 相关阅读:
    binder机制理解
    Android 资源目录
    Andriod 构建项目流程
    dpi、ppi 、dp、sp、px、 pt相关概念
    短语、直接短语和句柄
    MySql优化
    java虚拟机内存管理
    redis
    linux——nginx的安装及配置
    linux——高级文本处理命令之wc、cut、sort
  • 原文地址:https://www.cnblogs.com/danieljiang/p/majiang.html
Copyright © 2011-2022 走看看