题解 P5293 【[HNOI2019]白兔之舞】

officeyutong

2019-04-25 00:29:59

Solution

蒟蒻并不会单位根反演,但是从朴素的DP也能推出来一样的东西qwq (如果图片无法显示可以去https://yutong.site/?p=1388) ![](https://i.loli.net/2019/04/25/5cc08e6ab8cf3.png) 题外话:洛谷什么时候能支持多行Latex啊qwq.. ```cpp #include <assert.h> #include <algorithm> #include <cmath> #include <cstring> #include <fstream> #include <iostream> #include <vector> // #include using int_t = long long int; using std::cin; using std::cout; using std::endl; using real_t = double; using cpx_t = struct complex; const int_t LARGE = 5e5; const real_t PI = acos(-1); struct complex { real_t real, imag; complex(real_t a = 0, real_t b = 0) : real(a), imag(b) {} complex operator+(const complex& rhs) const { return complex{real + rhs.real, imag + rhs.imag}; } complex operator-(const complex& rhs) const { return complex{real - rhs.real, imag - rhs.imag}; } complex operator*(const complex& rhs) const { return complex{real * rhs.real - imag * rhs.imag, real * rhs.imag + imag * rhs.real}; } complex& operator*=(const complex& rhs) { *this = (*this) * rhs; return *this; } complex conj() .{ return complex{real, -imag}; } }; void transform(cpx_t* A, int size2, int arg); void poly_mul(const int* A, int n, const int* B, int m, int* A0, int p); // void transformX(int* A, int len, int g, int mod); void transformNTT(int* A, int size2, int arg, int mod, int g); std::vector<int> poly_dc_mul(const std::vector<int>& A); void poly_inv(const int* A, int n, int* result); void poly_div(const int* A, int n, const int* B, int m, int* R); std::vector<int> poly_eval(const std::vector<int>& poly, const std::vector<int>& vals); void transformX(int* A0, int len, int g); int power(int_t base, int_t index, int_t mod) { int result = 1; // base = (base % mod + mod) % mod; index = (index % (mod - 1) + mod - 1) % (mod - 1); while (index) { if (index & 1) result = (int_t)result * base % mod; index >>= 1; base = (int_t)base * base % mod; } assert(result >= 0); return result; } int_t mod; struct Matrix { int_t n; int_t data[4][4]; int_t* operator[](int_t r) { return data[r]; } int_t at(int_t r, int_t c) const { return data[r][c]; } Matrix(int_t n) { this->n = n; memset(data, 0, sizeof(data)); } Matrix operator*(const Matrix& rhs) const { Matrix result(n); for (int_t i = 1; i <= n; i++) { for (int_t j = 1; j <= n; j++) { for (int_t k = 1; k <= n; k++) { result[i][j] = (at(i, k) * rhs.at(k, j) % mod + mod + result[i][j]) % mod; } } } return result; } Matrix pow(int_t index) const { Matrix base = *this, result(n); for (int_t i = 1; i <= n; i++) result[i][i] = 1; while (index) { if (index & 1) result = result * base; base = base * base; index >>= 1; } return result; } }; int_t n, k, l, x, y; int_t mat[4][4]; Matrix makeMatrix(int_t x0) { Matrix result(n); for (int_t i = 1; i <= n; i++) for (int_t j = 1; j <= n; j++) { result[i][j] = x0 * mat[i][j] % mod; if (i == j) result[i][j] += 1; result[i][j] %= mod; } return result; } std::ostream& operator<<(std::ostream& os, const Matrix& mat) { for (int_t i = 1; i <= mat.n; i++) { for (int_t j = 1; j <= mat.n; j++) { os << mat.at(i, j) << " "; } cout << endl; } return os; } int flips[20][LARGE]; const auto flip = [=](int x, int size2) { int result = 0; for (int i = 1; i < size2; i++) { result |= (x & 1); x >>= 1; result <<= 1; } return result | (x & 1); }; int main() { for (int i = 1; i < 19; i++) { for (int j = 1; j < (1 << i); j++) flips[i][j] = flip(j, i); } cin >> n >> k >> l >> x >> y >> mod; for (int_t i = 1; i <= n; i++) for (int_t j = 1; j <= n; j++) cin >> mat[i][j]; Matrix M0(n); static int A[LARGE + 1]; M0[1][x] = 1; int_t g = 2; std::vector<int_t> divs; int_t px = mod - 1; assert(px % k == 0); for (int_t i = 2; i * i <= px; i++) { if (px % i == 0) { divs.push_back(i); if (i * i != px) divs.push_back(px / i); } } for (; g <= mod - 2; g++) { bool ok = true; for (int_t x : divs) { if (power(g, x, mod) == 1 && x != mod - 1) { ok = false; break; } } if (ok) break; } for (int_t i = 0; i < k; i++) { int_t gx = power(g, (mod - 1) / k * i, mod); auto T = makeMatrix(gx); A[i] = (M0 * T.pow(l))[1][y]; } transformX(A, k, g); const int_t leninv = power(k, mod - 2, mod); for (int_t i = 0; i < k; i++) printf("%lld\n", A[i] * leninv % mod); return 0; } void transformX(int* A0, int len, int g) { const auto C2 = [](int_t n) -> int_t { return n * (n - 1) / 2; }; int root = power(g, (mod - 1) / len, mod); static int A[LARGE + 1], B[LARGE + 1], A1[LARGE + 1]; for (int i = 0; i <= len * 2; i++) { A[i] = power(root, -C2(i), mod); } for (int i = 0; i < len; i++) { B[i] = (int_t)A0[i] * power(root, C2(i), mod) % mod; } std::reverse(B, B + len + 1); poly_mul(A, len * 2, B, len, A1, mod); for (int i = 0; i < len; i++) A0[i] = (int_t)A1[i + len] % mod * power(root, C2(i), mod) % mod; } void poly_mul(const int* A, int n, const int* B, int m, int* A0, int p) { int size2 = 0; while ((1 << size2) < n + m + 1) size2++; int len = (1 << size2); const int px = 3e4; static cpx_t C[LARGE + 1], D[LARGE + 1], G[LARGE + 1], Px[LARGE + 1]; for (int i = 0; i < len; i++) { if (i <= n) { C[i] = cpx_t{A[i] / px}; D[i] = cpx_t{A[i] % px}; } else { C[i] = D[i] = cpx_t(); } if (i <= m) { G[i] = cpx_t{B[i] / px, B[i] % px}; } else { G[i] = cpx_t{0, 0}; } } transform(C, size2, 1); transform(D, size2, 1); transform(G, size2, 1); for (int_t i = 0; i < len; i++) { C[i] = C[i] * G[i]; D[i] = D[i] * G[i]; } transform(C, size2, -1); transform(D, size2, -1); const auto make = [=](real_t x) -> int_t { assert(x / len >= -1); return (x / len) + 0.5; }; for (int i = 0; i <= n + m; i++) { A0[i] = ((int_t)make(C[i].real) % p * px % p * px % p + (int_t)make(C[i].imag + D[i].real) % p * px % p + make(D[i].imag) % p) % p; } } void transform(cpx_t* A, int size2, int arg) { int len = (1 << size2); for (int i = 0; i < len; i++) { int x = flips[size2][i]; if (x > i) std::swap(A[i], A[x]); } for (int i = 2; i <= len; i *= 2) { for (int j = 0; j < len; j += i) { for (int k = 0; k < i / 2; k++) { auto u = A[j + k], t = cpx_t(cos(2 * PI / i * k), sin(2 * PI / i * k) * arg) * A[j + k + i / 2]; A[j + k] = u + t; A[j + k + i / 2] = u - t; } } } } ```