记录编号 |
371946 |
评测结果 |
AAAAAAAAAA |
题目名称 |
[BZOJ 3456] 城市规划 |
最终得分 |
100 |
用户昵称 |
FoolMike |
是否通过 |
通过 |
代码语言 |
C++ |
运行时间 |
3.243 s |
提交时间 |
2017-02-17 13:38:21 |
内存使用 |
9.29 MiB |
显示代码纯文本
- #include <cstdio>
- #include <algorithm>
-
- using std::swap;
- using std::fill;
- using std::copy;
- using std::reverse;
- using std::reverse_copy;
-
- typedef int value_t;
- typedef long long calc_t;
- const int MaxN = 1 << 18;
- const value_t mod_base = 479, mod_exp = 21;
- const value_t mod_v = (mod_base << mod_exp) + 1;
- const value_t primitive_root = 3;
- int epsilon_num;
- value_t eps[MaxN], inv_eps[MaxN];
-
- value_t dec(value_t x, value_t v) { x -= v; return x < 0 ? x + mod_v : x; }
- value_t inc(value_t x, value_t v) { x += v; return x >= mod_v ? x - mod_v : x; }
- value_t pow(value_t x, value_t p)
- {
- value_t v = 1;
- for(; p; p >>= 1, x = (calc_t)x * x % mod_v)
- if(p & 1) v = (calc_t)x * v % mod_v;
- return v;
- }
-
- void init_eps(int num)
- {
- epsilon_num = num;
- value_t base = pow(primitive_root, (mod_v - 1) / num);
- value_t inv_base = pow(base, mod_v - 2);
- eps[0] = inv_eps[0] = 1;
- for(int i = 1; i != num; ++i)
- {
- eps[i] = (calc_t)eps[i - 1] * base % mod_v;
- inv_eps[i] = (calc_t)inv_eps[i - 1] * inv_base % mod_v;
- }
- }
-
- void transform(int n, value_t *x, value_t *w = eps)
- {
- for(int i = 0, j = 0; i != n; ++i)
- {
- if(i > j) swap(x[i], x[j]);
- for(int l = n >> 1; (j ^= l) < l; l >>= 1);
- }
-
- for(int i = 2; i <= n; i <<= 1)
- {
- int m = i >> 1, t = epsilon_num / i;
- for(int j = 0; j < n; j += i)
- {
- for(int p = 0, q = 0; p != m; ++p, q += t)
- {
- value_t z = (calc_t)x[j + m + p] * w[q] % mod_v;
- x[j + m + p] = dec(x[j + p], z);
- x[j + p] = inc(x[j + p], z);
- }
- }
- }
- }
-
- void inverse_transform(int n, value_t *x)
- {
- transform(n, x, inv_eps);
- value_t inv = pow(n, mod_v - 2);
- for(int i = 0; i != n; ++i)
- x[i] = (calc_t)x[i] * inv % mod_v;
- }
-
- struct poly_t
- {
- int deg;
- value_t x[MaxN];
- poly_t() : deg(0) { x[0] = 0; }
- };
-
- void polynomial_inverse(int n, const poly_t& A, poly_t& B)
- {
- if(n == 1)
- {
- B.deg = 1;
- B.x[0] = pow(A.x[0], mod_v - 2);
- return;
- }
-
- static value_t X[MaxN];
- polynomial_inverse((n + 1) >> 1, A, B);
-
- int p = 1;
- for(; p < n << 1; p <<= 1);
- copy(A.x, A.x + n, X);
- fill(X + n, X + p, 0);
- transform(p, X);
-
- fill(B.x + B.deg, B.x + p, 0);
- transform(p, B.x);
-
- for(int i = 0; i != p; ++i)
- B.x[i] = (calc_t)B.x[i] * dec(2, (calc_t)X[i] * B.x[i] % mod_v) % mod_v;
- inverse_transform(p, B.x);
- B.deg = n;
- }
-
- poly_t A, B, C;
- value_t inv[MaxN], inv_fac[MaxN], choose[MaxN];
-
- int main()
- {
- freopen("bzoj_3456.in","r",stdin);
- freopen("bzoj_3456.out","w",stdout);
- int n;
- std::scanf("%d", &n);
- int p = 1;
- for(; p < (n + 1) << 1; p <<= 1);
- init_eps(p);
-
- inv[1] = inv_fac[0] = 1;
- for(int i = 1; i <= n; ++i)
- {
- if(i != 1) inv[i] = -mod_v / i * (calc_t)inv[mod_v % i] % mod_v;
- if(inv[i] < 0) inv[i] += mod_v;
- inv_fac[i] = (calc_t)inv_fac[i - 1] * inv[i] % mod_v;
- }
-
- choose[0] = choose[1] = 1;
- for(int i = 2; i <= n; ++i)
- choose[i] = pow(2, (calc_t)i * (i - 1) / 2 % (mod_v - 1));
-
- A.deg = B.deg = n + 1;
- for(int i = 0; i <= n; ++i)
- A.x[i] = (calc_t)choose[i] * inv_fac[i] % mod_v;
- for(int i = 1; i <= n; ++i)
- B.x[i] = (calc_t)choose[i] * inv_fac[i - 1] % mod_v;
- polynomial_inverse(n + 1, A, C);
- fill(C.x + C.deg, C.x + p, 0);
- transform(p, C.x);
- transform(p, B.x);
- for(int i = 0; i <= p; ++i)
- C.x[i] = (calc_t)C.x[i] * B.x[i] % mod_v;
- inverse_transform(p, C.x);
- value_t ans = (calc_t)C.x[n] * pow(inv_fac[n - 1], mod_v - 2) % mod_v;
- if(ans < 0) ans += mod_v;
- std::printf("%d\n", ans);
- return 0;
- }