记录编号 371946 评测结果 AAAAAAAAAA
题目名称 [BZOJ 3456] 城市规划 最终得分 100
用户昵称 GravatarFoolMike 是否通过 通过
代码语言 C++ 运行时间 3.243 s
提交时间 2017-02-17 13:38:21 内存使用 9.29 MiB
显示代码纯文本
  1. #include <cstdio>
  2. #include <algorithm>
  3. using std::swap;
  4. using std::fill;
  5. using std::copy;
  6. using std::reverse;
  7. using std::reverse_copy;
  8. typedef int value_t;
  9. typedef long long calc_t;
  10. const int MaxN = 1 << 18;
  11. const value_t mod_base = 479, mod_exp = 21;
  12. const value_t mod_v = (mod_base << mod_exp) + 1;
  13. const value_t primitive_root = 3;
  14. int epsilon_num;
  15. value_t eps[MaxN], inv_eps[MaxN];
  16. value_t dec(value_t x, value_t v) { x -= v; return x < 0 ? x + mod_v : x; }
  17. value_t inc(value_t x, value_t v) { x += v; return x >= mod_v ? x - mod_v : x; }
  18. value_t pow(value_t x, value_t p)
  19. {
  20. value_t v = 1;
  21. for(; p; p >>= 1, x = (calc_t)x * x % mod_v)
  22. if(p & 1) v = (calc_t)x * v % mod_v;
  23. return v;
  24. }
  25. void init_eps(int num)
  26. {
  27. epsilon_num = num;
  28. value_t base = pow(primitive_root, (mod_v - 1) / num);
  29. value_t inv_base = pow(base, mod_v - 2);
  30. eps[0] = inv_eps[0] = 1;
  31. for(int i = 1; i != num; ++i)
  32. {
  33. eps[i] = (calc_t)eps[i - 1] * base % mod_v;
  34. inv_eps[i] = (calc_t)inv_eps[i - 1] * inv_base % mod_v;
  35. }
  36. }
  37. void transform(int n, value_t *x, value_t *w = eps)
  38. {
  39. for(int i = 0, j = 0; i != n; ++i)
  40. {
  41. if(i > j) swap(x[i], x[j]);
  42. for(int l = n >> 1; (j ^= l) < l; l >>= 1);
  43. }
  44. for(int i = 2; i <= n; i <<= 1)
  45. {
  46. int m = i >> 1, t = epsilon_num / i;
  47. for(int j = 0; j < n; j += i)
  48. {
  49. for(int p = 0, q = 0; p != m; ++p, q += t)
  50. {
  51. value_t z = (calc_t)x[j + m + p] * w[q] % mod_v;
  52. x[j + m + p] = dec(x[j + p], z);
  53. x[j + p] = inc(x[j + p], z);
  54. }
  55. }
  56. }
  57. }
  58. void inverse_transform(int n, value_t *x)
  59. {
  60. transform(n, x, inv_eps);
  61. value_t inv = pow(n, mod_v - 2);
  62. for(int i = 0; i != n; ++i)
  63. x[i] = (calc_t)x[i] * inv % mod_v;
  64. }
  65. struct poly_t
  66. {
  67. int deg;
  68. value_t x[MaxN];
  69. poly_t() : deg(0) { x[0] = 0; }
  70. };
  71. void polynomial_inverse(int n, const poly_t& A, poly_t& B)
  72. {
  73. if(n == 1)
  74. {
  75. B.deg = 1;
  76. B.x[0] = pow(A.x[0], mod_v - 2);
  77. return;
  78. }
  79. static value_t X[MaxN];
  80. polynomial_inverse((n + 1) >> 1, A, B);
  81. int p = 1;
  82. for(; p < n << 1; p <<= 1);
  83. copy(A.x, A.x + n, X);
  84. fill(X + n, X + p, 0);
  85. transform(p, X);
  86. fill(B.x + B.deg, B.x + p, 0);
  87. transform(p, B.x);
  88. for(int i = 0; i != p; ++i)
  89. B.x[i] = (calc_t)B.x[i] * dec(2, (calc_t)X[i] * B.x[i] % mod_v) % mod_v;
  90. inverse_transform(p, B.x);
  91. B.deg = n;
  92. }
  93. poly_t A, B, C;
  94. value_t inv[MaxN], inv_fac[MaxN], choose[MaxN];
  95. int main()
  96. {
  97. freopen("bzoj_3456.in","r",stdin);
  98. freopen("bzoj_3456.out","w",stdout);
  99. int n;
  100. std::scanf("%d", &n);
  101. int p = 1;
  102. for(; p < (n + 1) << 1; p <<= 1);
  103. init_eps(p);
  104. inv[1] = inv_fac[0] = 1;
  105. for(int i = 1; i <= n; ++i)
  106. {
  107. if(i != 1) inv[i] = -mod_v / i * (calc_t)inv[mod_v % i] % mod_v;
  108. if(inv[i] < 0) inv[i] += mod_v;
  109. inv_fac[i] = (calc_t)inv_fac[i - 1] * inv[i] % mod_v;
  110. }
  111. choose[0] = choose[1] = 1;
  112. for(int i = 2; i <= n; ++i)
  113. choose[i] = pow(2, (calc_t)i * (i - 1) / 2 % (mod_v - 1));
  114. A.deg = B.deg = n + 1;
  115. for(int i = 0; i <= n; ++i)
  116. A.x[i] = (calc_t)choose[i] * inv_fac[i] % mod_v;
  117. for(int i = 1; i <= n; ++i)
  118. B.x[i] = (calc_t)choose[i] * inv_fac[i - 1] % mod_v;
  119. polynomial_inverse(n + 1, A, C);
  120. fill(C.x + C.deg, C.x + p, 0);
  121. transform(p, C.x);
  122. transform(p, B.x);
  123. for(int i = 0; i <= p; ++i)
  124. C.x[i] = (calc_t)C.x[i] * B.x[i] % mod_v;
  125. inverse_transform(p, C.x);
  126. value_t ans = (calc_t)C.x[n] * pow(inv_fac[n - 1], mod_v - 2) % mod_v;
  127. if(ans < 0) ans += mod_v;
  128. std::printf("%d\n", ans);
  129. return 0;
  130. }