@atcoder - AGC038E@ Gachapon


@説明@

乱数発生器は、種のNの数を生成します。
Aiは、確率SA =ΣAiを表し、i番目のパラメータの数があり、Iが生成される乱数発生器愛/ SAが存在するであろう。
数は、すべてのiについて一定の時間まで生成されるたびに、時間のi番目の数は> = Biが停止生成されます。
予想時間を停止するように求めて。

制約
1 <=愛、バイ、N、ΣAi、ΣBi<= 400。

入力
フォーム、次の入力:
N
A0 B0
A1 B1を

。AN-BN 1の1-

出力
出力は、時間のmod 998244353を期待します。

サンプル入力1
2
1 1
1 1
サンプル出力1
3

@solution - 1 @

まず予備的な変換を発行する:
tは、最初の時間tへの貢献を停止した場合。
私たちは、初めて1の寄与を停止していない、止まらなかった、初めて0 1回の投稿トンとして貢献することができ、...、T-1最初の時間は、1回の総貢献トンを停止していません。
紙幣P(i)はi番目の静止時間を停止していない、所望の停止時間が存在する確率を表し\(\ sum_ {i = 0} P(i)を\)

どのように需要のP(i)を考えてみましょう。
生成されたシーケンスX1所与、X2、...、Xiはj番目のタイム生成XJを表す場合、配列が得られる確率は、[X1] / SA * Aでなければならない / [X2] / SA * ... * A [XI] SA。
長さiの全てのための一つの経路を停止し、シーケンス確率を計算するが、しない(しかしされていないかもしれです)。
シーケンス確率を停止し、P(i)を取得するために-私たちは、lは、思考逆。

D [k]は、kはD [k]を回発生している意味に留意されたいです。すなわち、配列は全て1 <= K <= N満たすD [k]を停止している> = B [ K]。
いうQ [i]の確率は配列に対応する停止表し、がある:
\ [Q [I] = \ sum_ {D [J] \ GE B [J]} ^ {(\ sum_ {I = 1} ^ {N- } D [J])= I } \ FRAC {I!} {\ prod_ {J = 1} ^ {N}(D [j]が!)} * \ prod_ {J = 1} ^ {N}(\ FRAC {[J]} {SA })^ {D [j]} \]

なお、だけでなく、階乗分母に、コンボリューションが含まれています。この式。私たちは、指数生成関数の形でそれを書き換えることを検討してください。
:Q(x)は、インデックスqの関数を発生させる、ある注意
{(\ \ [Q(X)= \ prod_ {I = 1} ^ {N-}(\ sum_ {J = B [I]} \ FRACをFRAC {[J]} { SA} X)^ J} {J!})\\ = \ prod_ {i = 1} ^ {N}(E ^ {\ FRAC {[J]} {SA} X } - \のsum_ {J = 0 } ^ {B [I] -1} \ FRAC {(\ FRAC {[J]} {SA} X)^ J} {J})\]!

:P(x)を与えるために、P-指数生成関数を示す設定
。Q(X)= E ^ X \\ - - \ prod_ 1 = {I}} ^ {N-(E [P(X)= E ^ Xを\を^ {\ FRAC {[J ]} {SA}、X} - \ sum_ {J = 0} ^ {B [I] -1} \ FRAC {(\ FRAC {[J]} {SA} X)^ J} {J!})\ ]

このようなものは、暴力的なO((ΣB)^ 2 *することができ ΣA) スタート。
それぞれが展開に成長\(C_ {I、J} E ^ {\ FRAC {I} {SA} X} X ^ {J} \) 形式、式I、J満たす0 <= I <=Σ 、0 <= J <= ΣB。

私たちは、列挙I、J、その後、数\(C_ {I、J} E ^ {\ FRAC {I} {} SAのx}のx ^ {J} \) の回答に貢献。
トンに言及= I / SA。今無視\(C_ {I、J} \) そして最後に、次にによって。\(E ^ {TX} X ^ {jは} \) を与えるように拡張:
\ [E ^ {TX} X ^ J = \ sum_ {I = 0} \ FRAC {T ^ IX ^ {Iは+ J}} {私!} \]

ので\(X ^ {iが+ J } \) Pに対応する係数[iがjは+] /( !私はJ + 1)、 そうPシークオン[I jの+](iはjは+)によって必要とされる場合!。したがって貢献:
\ [S(J)= \ sum_ {0} T = I ^ I(Iは、J + 1)^ {\下線{J}} \]

どのように需要S(j)のそれ?特性の下降力によって\((I + 1)^ {\下線{J} - I ^ {\下線{J}} = J * I ^ {\下線{J-1}。} \) および派生与えるために合計列の数よりもプロセス:
\ [S(J)= \ sum_ {0} T = I ^ I(Iは、J + 1)^ {\下線{J}} \\ T * S(J)= \ sum_ {i = 1} T ^ I (iは+ J-1)^ {\下線は{jは}} \\(1-t)は* S(j)は、J!+ j個*の\のsum_ {i = 1} Tが= ^ I(iはJ-1 +) ^ {\下線{J-1}}はj個の*のS(J-1)= \]

このようにして得られた({J} {T}。1-S(1-J)FRAC \ S(J)= \)\
J = 0であるため、等比級数を加算する場合、すなわち\(S(0)= \ {FRAC。1. 1-T {}} \) そう\(S(J)=( \はFRAC {1} {1 } -t)+。1 ^ J} * {J!\)

Oの合計時間の複雑さ((ΣB)^ 2 *ΣA)。

@acceptedコード - 1 @

#include<cstdio>
const int MAXN = 400;
const int MOD = 998244353;
int inv[MAXN + 5];
struct mint{
    int x;
    mint(int _x=0) : x(_x) {}
    friend mint operator + (const mint &a, const mint &b) {return a.x + b.x >= MOD ? a.x + b.x - MOD : a.x + b.x;}
    friend mint operator - (const mint &a, const mint &b) {return a.x - b.x < 0 ? a.x - b.x + MOD : a.x - b.x;}
    friend mint operator * (const mint &a, const mint &b) {return 1LL * a.x * b.x % MOD;}
    friend mint operator / (const mint &a, const int &b) {return a * inv[b];}
};
mint pow_mod(mint b, int p) {
    mint ret = 1;
    while( p ) {
        if( p & 1 ) ret = ret*b;
        b = b*b;
        p >>= 1;
    }
    return ret;
}
void init() {
    inv[1] = 1;
    for(int i=2;i<=MAXN;i++)
        inv[i] = MOD - 1LL*inv[MOD%i]*(MOD/i)%MOD;
}
mint coef[MAXN + 5][MAXN + 5];
int A[MAXN + 5], B[MAXN + 5], N, SA, SB;
void read() {
    scanf("%d", &N);
    for(int i=0;i<N;i++)
        scanf("%d%d", &A[i], &B[i]), SA += A[i], SB += B[i];
}
mint tmp[MAXN + 5][MAXN + 5];
void get() {
    coef[0][0] = 1;
    for(int i=0;i<N;i++) {
        for(int j=0;j<=SA;j++)
            for(int k=0;k<=SB;k++)
                tmp[j][k] = coef[j][k], coef[j][k] = 0;
        mint p = mint(A[i]) / SA, f = MOD - 1;
        for(int l=0;l<B[i];l++,f=f/l*p)
            for(int j=0;j<=SA;j++)
                for(int k=l;k<=SB;k++)
                    coef[j][k] = coef[j][k] + f*tmp[j][k-l];
        for(int j=A[i];j<=SA;j++)
            for(int k=0;k<=SB;k++)
                coef[j][k] = coef[j][k] + tmp[j-A[i]][k];
    }
    for(int i=0;i<=SA;i++)
        for(int j=0;j<=SB;j++)
            coef[i][j] = 0 - coef[i][j];
    coef[SA][0] = coef[SA][0] + 1;
}
/*
let t = e^(x/S)
t^S - (t^Ai - (x*Ai/S)^j/j!)
*/
int solve() {
    mint ret = 0, f = 1;
    for(int j=0;j<=SB;j++,f=f*j)
        for(int i=0;i<=SA;i++) {
            mint p = mint(i) / SA;
            p = pow_mod(1 - p, MOD - 2 - j);
            ret = ret + coef[i][j]*p*f;
        }
    return ret.x;
}
int main() {
    init(), read(), get();
    printf("%d\n", solve());
}

@solution - 2 @

449その質問-この質問は簡単に連想させるUOJできました。
我々は解決することができる最小-最大と除外使用するようにしてください。

集合S = {X1、X2、...のために 、XM}、 我々はそれが最初のBi所望の時間の限界に達するリクエストします。
それとも、最初の時間を求めて、変換の問題は、tは要素バイ確率p(t)は、期待されたp(t)との和のいずれかに到達しません。
したがって、このセットの寄与は以下の通り:
\ [( - 1)+ 1} ^ {M * \のFRAC {SA} {\ SUM A [XI]} * \ sum_ {0 \ルDI <B [XI]} \ FRAC {(\和ジ) !} {\ PROD(ジ!)} * \ PROD(\ FRAC {[XI]} {\和A [XI]})^ {ジ} \]

先行\ - ((1)^ { M + 1} \)を忌避因子を収容するように、\(\ FRAC {SA} {\ SUM A [XI]} \)は、望ましくはポンピング数に設定されます。

もちろん、我々は各セットを列挙して、カウントすることはできません。寄与がどのように変化するか、追加要素yのセット内とみなさ:
[\( - 1)^ {M + 2} * \ FRAC {SA} {[Y] + \ SUM A [XI]} * \ sum_ {0 \ルディ<B [XI] } \ sum_ {0 \ルDY <B [Y]} \ FRAC {(DY +の\和ジ)!} {DY!* \ PROD(ジ!)} * \ PROD(\ FRAC {[XI]} { [Y] + \和A [XI]})^ {ジ} *(\ FRAC {[Y]} {[Y] + \和A [XI]})^ {DY} \]

我々は限定場合観測方程式により、予め設定された\(\ SUM A [XI] = P \)、\ (\ SUM DI = Q \)を、寄与がない場合、Y及びDYの添加が挙げ他の条件の影響。
Fと呼ぶ[i]が[P] [ Q] iは現在の設定の数の個数n示す前に検討されている\を(\ SUM A [XI] = P、\ SUM DI = Q \) 全てのp、値qおよび独立の製品。
Pとは無関係に、Q値実際\(( - {!}。1 DI)* \ {FRAC [XI] DI} ^ {} \)これについて取る転送中。

最後にF [N] [P] [ Q] アウトカウントへの寄与。
O(ΣBi)倍を超えない総転送、時間計算量はO((ΣBi)^ 2 *である愛)。

@acceptedコード - 2 @

#include<cstdio>
const int MOD = 998244353;
const int MAXN = 400;
int inv[MAXN + 5];
void init() {
    inv[1] = 1;
    for(int i=2;i<=MAXN;i++)
        inv[i] = MOD - 1LL*inv[MOD%i]*(MOD/i)%MOD;
}
struct modint{
    int x;
    modint(int _x=0):x(_x) {}
    friend modint operator + (modint x, modint y) {return (x.x + y.x) >= MOD ? x.x + y.x - MOD : x.x + y.x;}
    friend modint operator - (modint x, modint y) {return (x.x - y.x) < 0 ? x.x - y.x + MOD : x.x - y.x;}
    friend modint operator * (modint x, modint y) {return 1LL*x.x*y.x%MOD;}
    friend modint operator / (modint x, int k) {return x*inv[k];}
};
modint pow_mod(modint b, int p) {
    modint ret = 1;
    while( p ) {
        if( p & 1 ) ret = ret*b;
        b = b*b;
        p >>= 1;
    }
    return ret;
}
modint f[2][MAXN + 5][MAXN + 5];
int A[MAXN + 5], B[MAXN + 5], SA, SB;
int main() {
    init();
    int n; scanf("%d", &n);
    for(int i=0;i<n;i++)
        scanf("%d%d", &A[i], &B[i]), SA += A[i], SB += B[i];
    f[0][0][0] = MOD - 1;
    for(int i=0;i<n;i++) {
        for(int j=0;j<=SA;j++)
            for(int k=0;k<=SB;k++)
                f[1][j][k] = f[0][j][k];
        modint p = 1;
        for(int l=0;l<B[i];l++,p=p*A[i]/l)
            for(int j=A[i];j<=SA;j++)
                for(int k=l;k<=SB;k++)
                    f[0][j][k] = f[0][j][k] - f[1][j-A[i]][k-l]*p;
    }
    modint ans = 0;
    for(int j=1;j<=SA;j++) {
        modint p = 1, q = modint(SA)/j;
        for(int k=0;k<=SB;k++,p=p*k/j)
            ans = ans + f[0][j][k]*p*q;
    }
    printf("%d\n", ans.x);
}

@詳細@

メインの導出式は、実際には、コード自体ははるかに達成することは困難ではない、です。
この問題は、組み合わせ論と日常期待の確率の多くが含まれます。

おすすめ

転載: www.cnblogs.com/Tiw-Air-OAO/p/11736325.html