fork download
  1. #include <bits/stdc++.h>
  2.  
  3. using namespace std;
  4.  
  5. const int md = 998244353;
  6.  
  7. int add(int x, int y) {
  8. x += y;
  9. if (x >= md) {
  10. x -= md;
  11. }
  12. return x;
  13. }
  14.  
  15. int sub(int x, int y) {
  16. x -= y;
  17. if (x < 0) {
  18. x += md;
  19. }
  20. return x;
  21. }
  22.  
  23. int mul(int x, int y) {
  24. return (long long)x * y % md;
  25. }
  26.  
  27. int power(int x, int y) {
  28. int result = 1;
  29. for (; y; y >>= 1, x = mul(x, x)) {
  30. if (y & 1) {
  31. result = mul(result, x);
  32. }
  33. }
  34. return result;
  35. }
  36.  
  37. namespace ntt {
  38. int base = 1, root = -1, max_base = -1;
  39. vector<int> roots = {0, 1}, rev = {0, 1};
  40.  
  41. void init() {
  42. int temp = md - 1;
  43. max_base = 0;
  44. while (!(temp & 1)) {
  45. temp >>= 1;
  46. ++max_base;
  47. }
  48. root = 2;
  49. while (true) {
  50. if (power(root, 1 << max_base) == 1 && power(root, 1 << max_base - 1) != 1) {
  51. break;
  52. }
  53. ++root;
  54. }
  55. }
  56.  
  57. void ensure_base(int nbase) {
  58. if (max_base == -1) {
  59. init();
  60. }
  61. if (nbase <= base) {
  62. return;
  63. }
  64. assert(nbase <= max_base);
  65. rev.resize(1 << nbase);
  66. for (int i = 0; i < (1 << nbase); ++i) {
  67. rev[i] = rev[i >> 1] >> 1 | ((i & 1) << nbase - 1);
  68. }
  69. roots.resize(1 << nbase);
  70. while (base < nbase) {
  71. int z = power(root, 1 << max_base - 1 - base);
  72. for (int i = 1 << base - 1; i < 1 << base; ++i) {
  73. roots[i << 1] = roots[i];
  74. roots[i << 1 | 1] = mul(roots[i], z);
  75. }
  76. ++base;
  77. }
  78. }
  79.  
  80. void dft(vector<int> &a) {
  81. int n = a.size(), zeros = __builtin_ctz(n);
  82. ensure_base(zeros);
  83. int shift = base - zeros;
  84. for (int i = 0; i < n; ++i) {
  85. if (i < rev[i] >> shift) {
  86. swap(a[i], a[rev[i] >> shift]);
  87. }
  88. }
  89. for (int i = 1; i < n; i <<= 1) {
  90. for (int j = 0; j < n; j += i << 1) {
  91. for (int k = 0; k < i; ++k) {
  92. int x = a[j + k], y = mul(a[j + k + i], roots[i + k]);
  93. a[j + k] = add(x, y);
  94. a[j + k + i] = sub(x, y);
  95. }
  96. }
  97. }
  98. }
  99.  
  100. vector<int> padd(vector<int> a, vector<int> b) {
  101. if (a.size() < b.size()) {
  102. a.resize(b.size());
  103. }
  104. for (int i = 0; i < b.size(); ++i) {
  105. a[i] = add(a[i], b[i]);
  106. }
  107. return a;
  108. }
  109.  
  110. vector<int> psub(vector<int> a, vector<int> b) {
  111. if (a.size() < b.size()) {
  112. a.resize(b.size());
  113. }
  114. for (int i = 0; i < b.size(); ++i) {
  115. a[i] = sub(a[i], b[i]);
  116. }
  117. return a;
  118. }
  119.  
  120. vector<int> pmul(vector<int> a, vector<int> b, bool equal = false) {
  121. int need = a.size() + b.size() - 1, nbase = 0;
  122. while (1 << nbase < need) {
  123. ++nbase;
  124. }
  125. ensure_base(nbase);
  126. int size = 1 << nbase;
  127. a.resize(size);
  128. b.resize(size);
  129. dft(a);
  130. if (equal) {
  131. b = a;
  132. } else {
  133. dft(b);
  134. }
  135. int inv = power(size, md - 2);
  136. for (int i = 0; i < size; ++i) {
  137. a[i] = mul(mul(a[i], b[i]), inv);
  138. }
  139. reverse(a.begin() + 1, a.end());
  140. dft(a);
  141. a.resize(need);
  142. return a;
  143. }
  144.  
  145. vector<int> psqr(vector<int> a) {
  146. return pmul(a, a, true);
  147. }
  148.  
  149. vector<int> pinv(vector<int> a) {
  150. int n = a.size(), m = n + 1 >> 1;
  151. if (n == 1) {
  152. return vector<int> (1, power(a[0], md - 2));
  153. } else {
  154. vector<int> b = pinv(vector<int> (a.begin(), a.begin() + m));
  155. int need = n << 1, nbase = 0;
  156. while (1 << nbase < need) {
  157. ++nbase;
  158. }
  159. ensure_base(nbase);
  160. int size = 1 << nbase;
  161. a.resize(size);
  162. b.resize(size);
  163. dft(a);
  164. dft(b);
  165. int inv = power(size, md - 2);
  166. for (int i = 0; i < size; ++i) {
  167. a[i] = mul(mul(sub(2, mul(a[i], b[i])), b[i]), inv);
  168. }
  169. reverse(a.begin() + 1, a.end());
  170. dft(a);
  171. a.resize(n);
  172. return a;
  173. }
  174. }
  175.  
  176. vector<int> pdiv(vector<int> a, vector<int> b) {
  177. int n = a.size(), m = b.size();
  178. if (n < m) {
  179. return vector<int> ();
  180. }
  181. reverse(a.begin(), a.end());
  182. reverse(b.begin(), b.end());
  183. b.resize(n - m + 1);
  184. b = pmul(a, pinv(b));
  185. b.erase(b.begin() + n - m + 1, b.end());
  186. reverse(b.begin(), b.end());
  187. return b;
  188. }
  189.  
  190. vector<int> pmod(vector<int> a, vector<int> b) {
  191. int n = a.size(), m = b.size();
  192. if (n < m) {
  193. return a;
  194. }
  195. vector<int> c = pmul(pdiv(a, b), b);
  196. for (int i = 0; i < m - 1; ++i) {
  197. c[i] = sub(a[i], c[i]);
  198. }
  199. c.resize(m - 1);
  200. return c;
  201. }
  202. }
  203.  
  204. using ntt::padd;
  205. using ntt::psub;
  206. using ntt::pmul;
  207. using ntt::psqr;
  208. using ntt::pinv;
  209. using ntt::pdiv;
  210. using ntt::pmod;
  211.  
  212. int main() {
  213. #ifdef wxh010910
  214. freopen("input.txt", "r", stdin);
  215. #endif
  216. int n;
  217. scanf("%d", &n);
  218. vector<int> a(n), b(n);
  219. for (int i = 0; i < n; ++i) {
  220. scanf("%d", &a[i]);
  221. }
  222. for (int i = 0; i < n; ++i) {
  223. scanf("%d", &b[i]);
  224. }
  225.  
  226. function<vector<int>(int, int)> multiply_all = [&](int l, int r) {
  227. if (l == r) {
  228. return vector<int> {1, sub(0, a[l])};
  229. } else {
  230. int mid = l + r >> 1;
  231. return pmul(multiply_all(l, mid), multiply_all(mid + 1, r));
  232. }
  233. };
  234.  
  235. vector<vector<int>> segtree((n << 1) - 1);
  236.  
  237. function<void(int, int, int)> build = [&](int x, int l, int r) {
  238. if (l == r) {
  239. segtree[x] = vector<int> {sub(0, power(a[l], md - 2)), 1};
  240. } else {
  241. int y = l + r >> 1, z = x + (y - l + 1 << 1);
  242. build(x + 1, l, y);
  243. build(z, y + 1, r);
  244. segtree[x] = pmul(segtree[x + 1], segtree[z]);
  245. }
  246. };
  247.  
  248. function<void(int, int, int, vector<int>, vector<int>&)> evaluate = [&](int x, int l, int r, vector<int> f, vector<int> &answer) {
  249. f = pmod(f, segtree[x]);
  250. if (l == r) {
  251. answer[l] = f[0];
  252. } else {
  253. int y = l + r >> 1, z = x + (y - l + 1 << 1);
  254. evaluate(x + 1, l, y, f, answer);
  255. evaluate(z, y + 1, r, f, answer);
  256. }
  257. };
  258.  
  259. vector<int> f = pmul(b, multiply_all(0, n - 1)), p(n), q(n);
  260. f.resize(n);
  261. build(0, 0, n - 1);
  262. evaluate(0, 0, n - 1, f, p);
  263. int coef = 1;
  264. for (int i = 0; i < n; ++i) {
  265. coef = mul(coef, sub(0, a[i]));
  266. }
  267. for (int i = 0; i < n; ++i) {
  268. f[i] = mul(mul(n - i, segtree[0][i]), coef);
  269. }
  270. evaluate(0, 0, n - 1, f, q);
  271.  
  272. for (int i = 0; i < n; ++i) {
  273. printf("%d%c", mul(p[i], power(q[i], md - 2)), i == n - 1 ? '\n' : ' ');
  274. }
  275.  
  276. return 0;
  277. }
  278.  
Time limit exceeded #stdin #stdout 5s 0KB
stdin
Standard input is empty
stdout
Standard output is empty