ディレクトリ
@説明@
乱数発生器は、所与のパラメータ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));
}
詳細@
私は練習ファックように感じます。。。しかし、私は知恵が公式の正の解は明らかではないですよ。。。