• 【LOJ】#3042. 「ZJOI2019」麻将


    LOJ#3042. 「ZJOI2019」麻将

    如何判定一个集合牌有没有胡的子集是不是胡的

    就用一个(dp[j][k][0/1])表示有j个连续两个的串,有k个连续1个串,有没有对子,再记一下这个集合里的牌大于等于2的花色数有几个

    我们把(dp[j][k][0/1])和大于等于2的花色数作为一副牌的状态,然后给每个状态标号,做一个dp

    (f[i][j][S])表示考虑到第(i)种花色,有(j)张牌,状态标号是(S)的方案数,记录到第(j)张牌还没赢的方案数是(S(j)),那么期望就是(frac{sum_{j = 13}^{infty} S(j)}{(4n- 13)!})

    #include <bits/stdc++.h>
    #define fi first
    #define se second
    #define pii pair<int,int>
    #define mp make_pair
    #define pb push_back
    #define space putchar(' ')
    #define enter putchar('
    ')
    #define eps 1e-10
    #define MAXN 200005
    #define ba 47
    //#define ivorysi
    using namespace std;
    typedef long long int64;
    typedef unsigned int u32;
    typedef double db;
    template<class T>
    void read(T &res) {
        res = 0;T f = 1;char c = getchar();
        while(c < '0' || c > '9') {
        	if(c == '-') f = -1;
        	c = getchar();
        }
        while(c >= '0' && c <= '9') {
        	res = res * 10 +c - '0';
        	c = getchar();
        }
        res *= f;
    }
    template<class T>
    void out(T x) {
        if(x < 0) {x = -x;putchar('-');}
        if(x >= 10) {
        	out(x / 10);
        }
        putchar('0' + x % 10);
    }
    const int MOD = 998244353;
    int inc(int a,int b) {
        return a + b >= MOD ? a + b - MOD : a + b;
    }
    int mul(int a,int b) {
        return 1LL * a * b % MOD;
    }
    void update(int &x,int y) {
        x = inc(x,y);
    }
    void upmax(int &x,int y) {
        x = max(x,min(4,y));
    }
    int fpow(int x,int c) {
        int res = 1,t = x;
        while(c) {
            if(c & 1) res = mul(res,t);
            t = mul(t,t);
            c >>= 1;
        }
        return res;
    }
    int N;
    int cnt[105];
    struct state {
        int d[3][3];
        state() {memset(d,-1,sizeof(d));}
        friend state trans(const state &a,int t) {
            state c;
            for(int j = 0 ; j <= 2 ; ++j) {
                for(int k = 0 ; k <= 2 ; ++k) {
                    if(a.d[j][k] == -1) continue;
                    for(int i = 0 ; i <= min(2,t - j - k) ; ++i) {
                        upmax(c.d[k][i],a.d[j][k] + j + (t - j - k - i) / 3);
                    }
                }
            }
            return c;
        }
        friend state Max(const state &a,const state &b) {
            state t;
            for(int j = 0 ; j <= 2 ; ++j) {
                for(int k = 0 ; k <= 2 ; ++k) {
                    t.d[j][k] = max(a.d[j][k],b.d[j][k]);
                }
            }
            return t;
        }
        friend bool operator == (const state &a,const state &b) {
            for(int j = 0 ; j <= 2 ; ++j) {
                for(int k = 0 ; k <= 2 ; ++k) {
                    if(a.d[j][k] != b.d[j][k]) return false;
                }
            }
            return true;
        }
        friend bool operator != (const state &a,const state &b) {
            return !(a == b);
        }
        friend bool operator < (const state &a,const state &b) {
            for(int j = 0 ; j <= 2 ; ++j) {
                for(int k = 0 ; k <= 2 ; ++k) {
                    if(a.d[j][k] != b.d[j][k]) return a.d[j][k] < b.d[j][k];
                }
            }
            return false;
        }
    };
    struct MJ {
        state dp[2];int cnt;
        MJ() {cnt = 0;dp[0].d[0][0] = 0;}
        friend MJ Trans(const MJ &a,int t) {
            MJ c;
            c.dp[1] = trans(a.dp[1],t);
            if(t >= 2) c.dp[1] = Max(trans(a.dp[0],t - 2),c.dp[1]);
            c.dp[0] = trans(a.dp[0],t);
            if(t >= 2) c.cnt = min(a.cnt + 1,7);
            else c.cnt = a.cnt;
            return c;
        }
        friend bool operator == (const MJ &a,const MJ &b) {
            for(int i = 0 ; i < 2 ; ++i) if(a.dp[i] != b.dp[i]) return false;
            if(a.cnt != b.cnt) return false;
            return true;
        }
        friend bool operator < (const MJ &a,const MJ &b) {
            for(int i = 0 ; i < 2 ; ++i) if(a.dp[i] != b.dp[i]) return a.dp[i] < b.dp[i];
            if(a.cnt != b.cnt) return a.cnt < b.cnt;
            return false;
        }
        bool win() {
            if(cnt >= 7) return true;
            for(int i = 0 ; i <= 2 ; ++i) {
                for(int j = 0 ; j <= 2 ; ++j) {
                    if(dp[1].d[i][j] >= 4) return true;
                }
            }
            return false;
        }
        void print() {
            out(cnt);enter;
            for(int p = 0 ; p <= 1 ; ++p) {
                for(int j = 0 ; j <= 2 ; ++j) {
                    for(int k = 0 ; k <= 2 ; ++k) {
                        out(dp[p].d[j][k]);space;
                    }
                    enter;
                }
    
            }
        }
    }pool[100006];
    map<MJ,int> zz;
    int tot;
    int dp[2][405][5005],cur,fac[405],invfac[405];
    void dfs(MJ a) {
        if(zz.count(a)) return;
        if(a.win()) return;
        zz[a] = ++tot;pool[tot] = a;
        for(int i = 0 ; i <= 4 ; ++i) {
            dfs(Trans(a,i));
        }
    }
    int C(int n,int m) {
        if(n < m) return 0;
        return mul(fac[n],mul(invfac[m],invfac[n - m]));
    }
    void Solve() {
        read(N);
        int w,a;
        for(int i = 1 ; i <= 13 ; ++i) {
            read(w);read(a);
            cnt[w]++;
        }
        MJ t;
        dfs(t);
        dp[0][0][zz[t]] = 1;cur = 0;
        fac[0] = 1;
        for(int i = 1 ; i <= 400 ; ++i) fac[i] = mul(fac[i - 1],i);
        invfac[400] = fpow(fac[400],MOD - 2);
        for(int i = 399 ; i >= 0 ; --i) invfac[i] = mul(invfac[i + 1],i + 1);
        for(int i = 1 ; i <= N ; ++i) {
            memset(dp[cur ^ 1],0,sizeof(dp[cur ^ 1]));
            for(int j = 0 ; j <= 4 * (i - 1) ; ++j) {
                for(int h = 1 ; h <= tot ; ++h) {
                    if(!dp[cur][j][h]) continue;
                    for(int k = max(cnt[i],0) ; k <= 4 ; ++k) {
                        MJ nxt = Trans(pool[h],k);
                        if(nxt.win()) continue;
                        update(dp[cur ^ 1][j + k][zz[nxt]],mul(dp[cur][j][h],C(4 - cnt[i],k - cnt[i])));
                    }
                }
            }
            cur ^= 1;
        }
        int ans = 0;
        for(int j = 13 ; j <= 4 * N ; ++j) {
            for(int h = 1 ; h <= tot ; ++h) {
                update(ans,mul(dp[cur][j][h],mul(fac[j - 13],fac[4 * N - j])));
            }
        }
        ans = mul(ans,invfac[4 * N - 13]);
        out(ans);enter;
    }
    int main() {
    #ifdef ivorysi
        freopen("f1.in","r",stdin);
    #endif
        Solve();
        return 0;
    }
    
    
  • 相关阅读:
    postman简单传参,上个接口的返回值作为下个接口的入参。
    python 给定URL 如何获取其内容,并将其保存至HTML文档。
    外键关联on_delete参数含义
    excel导入与导出
    序列化关系
    使用框架的各种代码示例
    国产celery简单使用
    selecte_related 函数优化查询
    django 之 配置文件
    类与缓存问题 类与属性的关系
  • 原文地址:https://www.cnblogs.com/ivorysi/p/10959425.html
Copyright © 2020-2023  润新知