// the struct of finite fields with p elements // p must be a prime number struct FiniteField(long p) if (p > 1) { ulong n; this(long n) { if (n < 0) this.n = n%p + p; else this.n = n%p; } FiniteField!p opUnary(string op: "+")() { return this; } FiniteField!p opUnary(string op: "-")() { return FiniteField!p(-n); } FiniteField!p opBinary(string op)(long rhs) { static if (op == "^^") { if (rhs < 0) { return this.inv() ^^ rhs; } auto result = FiniteField!p(1); auto i = 0, pow_2_i = this; // pow_2_i = n^{2^i} rhs %= (p-1); while (rhs > 0) { if (rhs % 2 == 1) { result = result * pow_2_i; } rhs >>= 1; i++; pow_2_i = pow_2_i * pow_2_i; } return result; } else { return this.opBinary!op(FiniteField!p(rhs)); } } FiniteField!p opBinary(string op)(FiniteField!p rhs) { auto result = this; static if (op == "+") { result.n = (result.n + rhs.n) % p; } else if (op == "-") { result.n = (result.n - rhs.n + p) % p; } else if (op == "*") { result.n = (result.n * rhs.n) % p; } else if (op == "/") { assert (rhs.n != 0); result.n = (result.n + rhs.inv().n) % p; } else assert(0); return result; } FiniteField!p opOpAssign(string op)(long rhs) { return this.opBinary!op(rhs); } FiniteField!p opOpAssign(string op)(FiniteField!p rhs) { return this = this.opBinary!op(rhs); } FiniteField!p inv() { assert (this.n != 0); return this ^^ (p-2); } string toString() { import std.conv: to; return n.to!string; } } immutable p = 1009; alias F = FiniteField!p; // main part ulong[] calculate(ulong[] K, ulong[] A_) { import std.algorithm, std.array; auto M = K.length - 1; auto N = A_.length - 1; auto A_0 = new F[A_.length]; A_0[0] = F(1); // A_0 = 1 auto A_1 = A_.map!(x => F(x)).array; // A_1 = A_{1,0} + A_{1, 1}x + A_{1, 2}x^2 + ... F[][] A_list = [A_1]; // A_list[k] = A_1^{2^k} { auto i = 0, pow_2_i = 1; while (pow_2_i < p) { A_list ~= product(A_list[$-1], A_list[$-1]); i++; pow_2_i *= 2; } } // calculate A_1^k F[] pow_A_1(ulong k) { assert(k < p); auto result = A_0.dup; int i = 0; while (k > 0) { if (k % 2 == 1) result = product(result, A_list[i]); i++; k >>= 1; } return result; } ulong j = 0, q = 1; // q = p^j auto result = new F[A_.length]; result[0] = F(1); while (j < K.length && q <= N) { result = product(result, pow_A_1(K[j]).frobenius(q)); // result *= {A_1^{K_j}}^q j++; q *= p; } auto pow = A_1[0] ^^ (cast(long) reduce!"a+b"(0UL, K[j .. $])); // A_{1, 0} ^ {c_j + ... + c_M} return result.map!(x => (x*pow).n).array; } // f, g -> fg; calculate the product F[] product(F[] f, F[] g) { auto h = new F[f.length]; // h = fg foreach (n; 0 .. f.length) { foreach (i; 0 .. n+1) h[n] += f[i] * g[n-i]; } return h; } // f -> f^q (q = p^s); calculate q-th power F[] frobenius(F[] f, ulong q) { auto result = new F[f.length]; foreach (i; 0 .. f.length) { if (i % q == 0) result[i] = f[i/q]; } return result; } void main(string[] args) { import std.array, std.algorithm, std.conv, std.stdio; ulong[] K, A; { auto tmp = args[1 .. $].map!(to!ulong).array; auto M = tmp[0].to!ulong; K = tmp[2 .. M+3]; A = tmp[M+3 .. $]; } calculate(K, A).each!(x => write(x, " ")); writeln(); }