[关闭]
@qq290637843 2020-11-02T18:15:36.000000Z 字数 5254 阅读 224

Math Class

如果
那么

证明:

实际只需要,所以直接就可。
显然所以直接就得出了

有了,接着就是bluestein算法,算法核心是

  1. #include <bits/stdc++.h>
  2. using ul = std::uint32_t;
  3. using li = std::int32_t;
  4. using ll = std::int64_t;
  5. using ull = std::uint64_t;
  6. using ulll = __uint128_t;
  7. using llf = long double;
  8. using lf = double;
  9. using vul = std::vector<ul>;
  10. using vvul = std::vector<vul>;
  11. using pulb = std::pair<ul, bool>;
  12. using vpulb = std::vector<pulb>;
  13. using vvpulb = std::vector<vpulb>;
  14. using vb = std::vector<bool>;
  15. using vull = std::vector<ull>;
  16. const ull base = 4179340454199820289ull;
  17. ull plus(ull a, ull b)
  18. {
  19. return a + b < base ? a + b : a + b - base;
  20. }
  21. ull minus(ull a, ull b)
  22. {
  23. return a < b ? a + base - b : a - b;
  24. }
  25. ull mul(ull a, ull b)
  26. {
  27. ll tmp = ll(a) * ll(b) - ll(llf(a) * llf(b) / llf(base)) * ll(base);
  28. return tmp < 0 ? tmp + ll(base) : (tmp < base ? tmp : tmp - ll(base));
  29. }
  30. void exgcd(ll a, ll b, ll& x, ll& y)
  31. {
  32. if (b) {
  33. exgcd(b, a % b, y, x);
  34. y -= x * (a / b);
  35. } else {
  36. x = 1;
  37. y = 0;
  38. }
  39. }
  40. ull inverse(ull a)
  41. {
  42. ll x, y;
  43. exgcd(a, base, x, y);
  44. return x < 0 ? x + ll(base) : x;
  45. }
  46. ull pow(ull a, ull b)
  47. {
  48. ull ret = 1;
  49. ull temp = a;
  50. while (b) {
  51. if (b & 1) {
  52. ret = mul(ret, temp);
  53. }
  54. temp = mul(temp, temp);
  55. b >>= 1;
  56. }
  57. return ret;
  58. }
  59. class polynomial : public vull {
  60. public:
  61. void clearzero() {
  62. while (size() && !back()) {
  63. pop_back();
  64. }
  65. }
  66. polynomial()=default;
  67. polynomial(const vull& a): vull(a) { }
  68. polynomial(vull&& a): vull(std::move(a)) { }
  69. ul degree() const {
  70. return size() - 1;
  71. }
  72. };
  73. class ntt_t {
  74. public:
  75. static const ul lgsz = 21;
  76. static const ul sz = 1 << lgsz;
  77. static const ull g = 3;
  78. ull w[sz + 1];
  79. ull leninv[lgsz + 1];
  80. ntt_t() {
  81. ull wn = pow(g, (base - 1) >> lgsz);
  82. w[0] = 1;
  83. for (ul i = 1; i <= sz; ++i) {
  84. w[i] = mul(w[i - 1], wn);
  85. }
  86. leninv[lgsz] = inverse(sz);
  87. for (ul i = lgsz - 1; ~i; --i) {
  88. leninv[i] = plus(leninv[i + 1], leninv[i + 1]);
  89. }
  90. }
  91. void operator()(vull& v, ul& n, bool inv) {
  92. ul lgn = 0;
  93. while ((1 << lgn) < n) {
  94. ++lgn;
  95. }
  96. n = 1 << lgn;
  97. v.resize(n, 0);
  98. for (ul i = 0, j = 0; i != n; ++i) {
  99. if (i < j) {
  100. std::swap(v[i], v[j]);
  101. }
  102. ul k = n >> 1;
  103. while (k & j) {
  104. j &= ~k;
  105. k >>= 1;
  106. }
  107. j |= k;
  108. }
  109. for (ul lgmid = 0; (1 << lgmid) != n; ++lgmid) {
  110. ul mid = 1 << lgmid;
  111. ul len = mid << 1;
  112. for (ul i = 0; i != n; i += len) {
  113. for (ul j = 0; j != mid; ++j) {
  114. ull t0 = v[i + j];
  115. ull t1 = mul(w[inv ? (len - j << lgsz - lgmid - 1) : (j << lgsz - lgmid - 1)], v[i + j + mid]);
  116. v[i + j] = plus(t0, t1);
  117. v[i + j + mid] = minus(t0, t1);
  118. }
  119. }
  120. }
  121. if (inv) {
  122. for (ul i = 0; i != n; ++i) {
  123. v[i] = mul(v[i], leninv[lgn]);
  124. }
  125. }
  126. }
  127. } ntt;
  128. polynomial& operator*=(polynomial& a, const polynomial& b)
  129. {
  130. if (!b.size() || !a.size()) {
  131. a.resize(0);
  132. return a;
  133. }
  134. polynomial temp = b;
  135. ul npmp1 = a.size() + b.size() - 1;
  136. if (ull(a.size()) * ull(b.size()) <= ull(npmp1) * ull(50)) {
  137. temp.resize(0);
  138. temp.resize(npmp1, 0);
  139. for (ul i = 0; i != a.size(); ++i) {
  140. for (ul j = 0; j != b.size(); ++j) {
  141. temp[i + j] = plus(temp[i + j], mul(a[i], b[j]));
  142. }
  143. }
  144. a = temp;
  145. a.clearzero();
  146. return a;
  147. }
  148. ntt(a, npmp1, false);
  149. ntt(temp, npmp1, false);
  150. for (ul i = 0; i != npmp1; ++i) {
  151. a[i] = mul(a[i], temp[i]);
  152. }
  153. ntt(a, npmp1, true);
  154. a.clearzero();
  155. return a;
  156. }
  157. polynomial operator*(const polynomial& a, const polynomial& b)
  158. {
  159. polynomial ret = a;
  160. return ret *= b;
  161. }
  162. const ul maxp = 5e5;
  163. ul T;
  164. ul n, p;
  165. ul F[maxp];
  166. ul f[maxp];
  167. ul fac[maxp];
  168. ul fiv[maxp];
  169. polynomial tmp1;
  170. polynomial tmp2;
  171. std::vector<ul> facpm1;
  172. ul wpow[maxp - 1];
  173. void exgcd(li a, li b, li& x, li& y)
  174. {
  175. if (b) {
  176. exgcd(b, a % b, y, x);
  177. y -= a / b * x;
  178. } else {
  179. x = 1;
  180. y = 0;
  181. }
  182. }
  183. ul pow(ul a, ul b, ul mod)
  184. {
  185. ul ret = 1;
  186. while (b) {
  187. if (b & 1) {
  188. ret = ull(ret) * ull(a) % mod;
  189. }
  190. a = ull(a) * ull(a) % mod;
  191. b >>= 1;
  192. }
  193. return ret;
  194. }
  195. ull c2(ul x)
  196. {
  197. return ull(x) * ull(x - 1) / 2;
  198. }
  199. int main()
  200. {
  201. std::scanf("%u", &T);
  202. for (ul Case = 1; Case <= T; ++Case) {
  203. std::scanf("%u%u", &n, &p);
  204. fac[0] = 1;
  205. for (ul i = 1; i <= p - 1; ++i) {
  206. fac[i] = ull(fac[i - 1]) * ull(i) % p;
  207. }
  208. if (true) {
  209. li x, y;
  210. exgcd(fac[p - 1], p, x, y);
  211. if (x < 0) {
  212. x += p;
  213. }
  214. fiv[p - 1] = x;
  215. }
  216. for (ul i = p - 1; i >= 1; --i) {
  217. fiv[i - 1] = ull(fiv[i]) * ull(i) % p;
  218. }
  219. for (ul i = 0; i <= n; ++i) {
  220. std::scanf("%u", &F[i]);
  221. }
  222. tmp1.resize(n + 1);
  223. tmp2.resize(n + 1);
  224. for (ul i = 0; i <= n; ++i) {
  225. tmp1[i] = ull(F[i]) * ull(fiv[i]) % p;
  226. tmp2[i] = (i & 1) ? p - fiv[i] : fiv[i];
  227. }
  228. tmp1 *= tmp2;
  229. tmp1.resize(n + 1);
  230. for (ul i = 0; i <= n; ++i) {
  231. tmp1[i] %= p;
  232. }
  233. tmp1.resize(p);
  234. tmp2.resize(p);
  235. for (ul i = 0; i <= p - 1; ++i) {
  236. tmp2[i] = fiv[i];
  237. }
  238. tmp1 *= tmp2;
  239. tmp1.resize(p);
  240. for (ul i = 0; i <= p - 1; ++i) {
  241. F[i] = ull(tmp1[i] % p) * ull(fac[i]) % p;
  242. }
  243. ul pm1 = p - 1;
  244. facpm1.resize(0);
  245. for (ul i = 2; pm1 != 1; ++i) {
  246. while (pm1 % i == 0) {
  247. pm1 /= i;
  248. facpm1.push_back(i);
  249. }
  250. }
  251. ul w;
  252. pm1 = p - 1;
  253. for (w = 1; ; ++w) {
  254. bool flag = true;
  255. for (ul i : facpm1) {
  256. if (pow(w, pm1 / i, p) == 1) {
  257. flag = false;
  258. break;
  259. }
  260. }
  261. if (flag) {
  262. break;
  263. }
  264. }
  265. wpow[0] = 1;
  266. for (ul i = 1; i <= p - 2; ++i) {
  267. wpow[i] = ull(wpow[i - 1]) * ull(w) % p;
  268. }
  269. tmp1.resize(p - 1);
  270. for (ul i = 0; i <= p - 2; ++i) {
  271. tmp1[i] = ull(F[wpow[i]]) * ull(wpow[c2(i) % pm1]) % p;
  272. }
  273. tmp2.resize(p - 1 + p - 1);
  274. for (ul i = 0; i <= p + p - 3; ++i) {
  275. tmp2[p + p - 3 - i] = wpow[(pm1 - c2(i) % pm1) % pm1];
  276. }
  277. tmp1 *= tmp2;
  278. tmp1.resize(p - 1 + p - 1);
  279. for (ul i = 0; i <= n; ++i) {
  280. ul pos = p + p - 3 - i;
  281. f[i] = (p - ull(tmp1[pos] % p) * ull(wpow[c2(i) % pm1]) % p) % p;
  282. }
  283. std::printf("Case #%u:\n", Case);
  284. for (ul i = 0; i <= n; ++i) {
  285. if (i) {
  286. std::putchar(' ');
  287. }
  288. std::printf("%u", f[i]);
  289. }
  290. std::printf("\n");
  291. }
  292. return 0;
  293. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注