@atcoder - RNGとXOR @ AGC034F


@説明@

乱数発生器は、所与のパラメータA [0 ... 2 ^ N-所定の範囲[0、2 ^ N)における 1]。
発電機が持っている\(\ FRAC {a_iを} { \和A} \) 世代iの確率は、それぞれ独立して生成されます。

X、最初のゼロが用意されました。各操作の乱数とXの排他的VまたはVを生成する。テイク

毎回のX数の操作を求めるI∈[0、2 ^ N)は、最初に等しいiが望ましいです。

オリジナルタイトルタイトル顔

@解決@

期待がDP考えにくいです。DPの定義[i]を表し、iは、所望の回数に達し、その後:

\ [DP [0] = 0 \\ DP [I] =(\ sum_ {J = 0} ^ {2 ^ N - 1} DP [J] \回P [I \ oplus J])+ 1 \]

前記\(P [I] = \ FRAC a_iを{{} \} A SUM \)

シンプルなアプローチは、ガウスの消去法にあります。どうやらませんでした。
図構造を使用して、ガウス消去の日常的な最適化のための転送が、転送グラフの問題(例えばDAG、ツリー又はチェーンのように)完了し、できません。

方法は?構造の転送タイプを観察し、それが実際にXORの畳み込みであることがわかりました。我々はセットその生成機能を取るしようとして。

表記生成機能場合、と呼ぶことができる\(DP \ Oplus P + I = DP + K \時間T \) \(I [I] = 1 、T [I] = [I = 0] \)、\ (Kは\)は不明です。
n = 0の畳み込みが確立されていない場合、の終わりに記入する必要があることに注意してください\(K \時間T \)

与える形状可変ビット\( - P)= I - DP \ Oplus(T K \時間T \)を、両面が同時にFWT得る\(DP '\時間(T - = I ' - K \時刻T' P')を\) 。

注目' - \((T P) \) に0は、(定義によりFWTと理解される)は常にされる、0である- (K \回I \' T「\) 0のはこれによって、また0でありますこれは、kについて解くことができます。

しかし、この方法は、私たちが知らない\(DP「[0] \ ) もう一度、未知数qを設定されているどのくらい。ときは、それを代入し、未知での動作に逆変換します。

次に\(DP \)シリーズを含むQの線形関数として表すことができ、に従って\(DP [0] = 0 \) Q逆について解くことができるので、\(DP \)溶液上に一連。

@acceptedコード@

#include <cstdio>

const int MOD = 998244353;
const int INV2 = (MOD + 1) >> 1;

int add(int x, int y) {return (x + y >= MOD ? x + y - MOD : x + y);}
int sub(int x, int y) {return (x - y < 0 ? x - y + MOD : x - y);}
int mul(int x, int y) {return 1LL*x*y%MOD;}

int pow_mod(int b, int p) {
    int ret = 1;
    for(int i=p;i;i>>=1,b=mul(b,b))
        if( i & 1 ) ret = mul(ret,b);
    return ret;
}

struct node{
    int k, b;
    node() : k(0), b(0) {}
    node(int _k, int _b) : k(_k), b(_b) {}
    int get(int x) {return add(mul(k, x), b);}
    friend node operator + (node a, node b) {
        return node(add(a.k, b.k), add(a.b, b.b));
    }
    friend node operator - (node a, node b) {
        return node(sub(a.k, b.k), sub(a.b, b.b));
    }
    friend node operator * (node a, int k) {
        return node(mul(a.k, k), mul(a.b, k));
    }
    friend node operator / (node a, int k) {
        return a * pow_mod(k, MOD - 2);
    }
};

void fwt(node *A, int m, int type) {
    int n = (1 << m), f = (type == 1 ? 1 : INV2);
    for(int i=1;i<=m;i++) {
        int s = (1 << i), t = (s >> 1);
        for(int j=0;j<n;j+=s)
            for(int k=0;k<t;k++) {
                node x = A[j+k], y = A[j+k+t];
                A[j+k] = (x + y)*f, A[j+k+t] = (x - y)*f;
            }
    }
}

node A[1<<18], B[1<<18], C[1<<18], f[1<<18];

int main() {
    int N, M, S = 0; scanf("%d", &N), M = (1 << N);
    for(int i=0;i<M;i++) scanf("%d", &A[i].b), S = add(S, A[i].b);
    S = pow_mod(S, MOD - 2);
    for(int i=0;i<M;i++) A[i].b = sub(i == 0 ? 1 : 0, mul(A[i].b, S));
    for(int i=0;i<M;i++) B[i].b = 1;
    C[0].b = MOD - 1;
    fwt(A, N, 1), fwt(B, N, 1), fwt(C, N, 1);
    int tmp = mul(B[0].b, pow_mod(C[0].b, MOD-2));
    for(int i=1;i<M;i++)
        f[i] = (B[i] - C[i]*tmp) / A[i].b;
    f[0].k = 1; fwt(f, N, -1);
    int x = sub(0, mul(pow_mod(f[0].k, MOD-2), f[0].b));
    for(int i=0;i<M;i++) printf("%d\n", f[i].get(x));
}

詳細@

私は練習ファックように感じます。しかし、私は知恵が公式の正の解は明らかではないですよ。

おすすめ

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