zoukankan      html  css  js  c++  java
  • 【题解】Luogu P5279 [ZJOI2019]麻将

    原题传送门

    希望这题不会让你对麻将的热爱消失殆尽

    我们珂以统计每种牌出现的次数,不需要统计是第几张牌

    判一副牌能不能和,类似这道题

    对于这题:

    (f[i][j][k][0/1])表示前(i)种牌,顺子((i-1,i,i+1))出现了(j)次,顺子((i,i+1,i+2))出现了(k)次,有/没有雀头的最多面子数。转移比较简单

    我们珂以发现(j)这维不太重要,强制dp值不超过(4)(超过(4)也没有用),雀头数不超过(7)(类似),爆搜珂以搜出本质不同的状态一共有(2091)

    珂以在每个状态珂以在后面加(x in [0,4])张点数+1的牌,这珂以构成一个自动机,我们叫她和牌自动机

    我们每得到一个状态,珂以在和牌自动机上走,判断是否能和

    我们设(dp[i][j][k])表示看到前(i)种牌,在和牌自动机上的(j)状态,已经摸了(k)张牌,不胡的种类数,最后算一下期望就珂以了

    我们珂以用滚动数组把(i)滚掉优化空间

    #include <bits/stdc++.h>
    #define mod 998244353
    #define N 405
    #define getchar nc
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register 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;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    inline int Min(register int a,register int b)
    {
        return a<b?a:b;
    }
    inline int Max(register int a,register int b)
    {
        return a>b?a:b;
    }
    struct node{
        int f[3][3][2],cnt;
        inline void init()
        {
            memset(f,-1,sizeof(f));
            f[0][0][0]=cnt=0;
        }
        inline int hu()
        {
            if(cnt>=7)
                return 1;
            for(register int i=0;i<3;++i)
                for(register int j=0;j<3;++j)
                    if(f[i][j][1]>=4)
                        return 1;
            return 0;
        }
    }rt,S[2100];
    bool operator < (node a,node b){
        if(a.cnt!=b.cnt)
            return a.cnt<b.cnt;
        for(register int i=0;i<3;++i)
            for(register int j=0;j<3;++j)
                for(register int k=0;k<2;++k)
                    if(a.f[i][j][k]!=b.f[i][j][k])
                        return a.f[i][j][k]<b.f[i][j][k];
        return 0;
    }
    int tot=0;
    map<node,int> ma;
    inline node trans(register node u,register int w)
    {
        node v;
        v.init();
        v.cnt=Min(u.cnt+(w>=2),7);
        for(register int i=0;i<3;++i)
            for(register int j=0;j<3;++j)
            {
                if(~u.f[i][j][0])
                {
                    for(register int k=0;k<3&&i+j+k<=w;++k)	
                        v.f[j][k][0]=Max(v.f[j][k][0],Min(u.f[i][j][0]+i+(w-i-j-k>=3),4));
                    if(w>=2)
                        for(register int k=0;k<3&&i+j+k<=w-2;++k)
                            v.f[j][k][1]=Max(v.f[j][k][1],Min(u.f[i][j][0]+i,4));
                }
                if(~u.f[i][j][1])
                    for(register int k=0;k<3&&i+j+k<=w;++k)
                        v.f[j][k][1]=Max(v.f[j][k][1],Min(u.f[i][j][1]+i+(w-i-j-k>=3),4));
            }
        return v;
    }
    inline void build(register node u)
    {
        if(u.hu())
            return;
        if(ma.find(u)!=ma.end())
            return;
        ma[u]=++tot;
        S[tot]=u;
        for(register int i=0;i<=4;++i)
            build(trans(u,i));
    }
    int n,s[N],ans;
    int fac[N],inv[N],invf[N],tr[2100][5],f[2][2100][N];
    inline int C(register int n,register int m)
    {
        return 1ll*fac[n]*invf[m]%mod*invf[n-m]%mod;
    }
    int main()
    {
        rt.init();
        build(rt);
        invf[0]=inv[0]=inv[1]=fac[0]=1;
        for(register int i=1;i<N;++i)
            fac[i]=1ll*fac[i-1]*i%mod;
        for(register int i=2;i<N;++i)
            inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
        for(register int i=1;i<N;++i)
            invf[i]=1ll*invf[i-1]*inv[i]%mod;
        n=read();
        for(register int i=1;i<=13;++i)
            ++s[read()],read();
        for(register int i=1;i<=tot;++i)
            for(register int j=0;j<=4;++j)
                tr[i][j]=ma[trans(S[i],j)];
        f[0][1][0]=1;
        for(register int i=1,sum=0;i<=n;++i)
        {
            int now=i&1,pre=now^1;
            memset(f[now],0,sizeof(f[now]));
            for(register int j=1;j<=tot;++j)
                for(register int k=s[i];k<=4;++k)
                {
                    if(!tr[j][k])
                        continue;
                    int w=1ll*C(4-s[i],k-s[i])*fac[k-s[i]]%mod;
                    for(register int l=0;l<=4*n-k;++l)
                    {
                        if(!f[pre][j][l])
                            continue;
                        f[now][tr[j][k]][l+k]=(0ll+f[now][tr[j][k]][l+k]+1ll*f[pre][j][l]*w%mod*C(k+l-sum-s[i],k-s[i])%mod)%mod;
                    }
                }
            sum+=s[i];
        }
        for(register int i=13,w=1;i<=4*n;++i)
        {
            int now=0;
            for(register int j=1;j<=tot;++j)
                now=(0ll+now+f[n&1][j][i])%mod;
            ans=(0ll+ans+1ll*now*w%mod)%mod;
            w=1ll*w*inv[4*n-i]%mod;
        }
        write(ans);
        return 0;
    }
    
  • 相关阅读:
    20199124 2019-2020-2《网络攻防实践》第8周作业
    20199124 2019-2020-2《网络攻防实践》第7周作业
    20199124 2019-2020-2《网络攻防实践》第6周作业
    20199124 2019-2020-2 《网络攻防实践》-第5周作业
    20199124 2019-2020-2 《网络攻防实践》第4周作业
    20199124 2019-2020-2 《网络攻防实践》第3周作业
    20199124 2019-2020-2 《网络攻防实践》第2周作业
    20199124 2019-2020-2 《网络攻防实践》第1周作业
    《网络攻防实践》假期作业
    《构建之法》第一章学习总结
  • 原文地址:https://www.cnblogs.com/yzhang-rp-inf/p/10993547.html
Copyright © 2011-2022 走看看