Skip to content

Commit 95928af

Browse files
committed
Improve linrec consecutive
1 parent 8f96ad5 commit 95928af

File tree

3 files changed

+33
-16
lines changed

3 files changed

+33
-16
lines changed

cp-algo/math/poly.hpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -630,8 +630,11 @@ namespace cp_algo::math {
630630
}
631631
// [x^k]..[x^{k+n-1}] of inv()
632632
// supports negative k if k+n >= 0
633+
poly_t& inv_inplace(int64_t k, size_t n) {
634+
return poly::impl::inv_inplace(*this, k, n);
635+
}
633636
poly_t inv(int64_t k, size_t n) const {
634-
return poly::impl::inv(*this, k, n);
637+
return poly_t(*this).inv_inplace(k, n);;
635638
}
636639

637640
// compute A(B(x)) mod x^n in O(n^2)

cp-algo/math/poly/impl/div.hpp

Lines changed: 28 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -70,25 +70,38 @@ namespace cp_algo::math::poly::impl {
7070
}
7171
return powmod_hint(p, k, md, md.reverse().inv(md.deg() + 1));
7272
}
73-
74-
auto interleave(auto const& p) {
75-
auto [p0, p1] = p.bisect();
76-
return p0 * p0 - (p1 * p1).mul_xk(1);
77-
}
7873
template<typename poly>
79-
poly inv(poly const& q, int64_t k, size_t n) {
74+
poly& inv_inplace(poly& q, int64_t k, size_t n) {
75+
using poly_t = std::decay_t<poly>;
76+
using base = poly_t::base;
8077
if(k <= std::max<int64_t>(n, size(q.a))) {
81-
return q.inv(k + n).div_xk(k);
78+
return q.inv_inplace(k + n).div_xk_inplace(k);
8279
}
8380
if(k % 2) {
84-
return inv(q, k - 1, n + 1).div_xk(1);
81+
return inv_inplace(q, k - 1, n + 1).div_xk_inplace(1);
8582
}
86-
87-
auto qq = inv(interleave(q), k / 2 - q.deg() / 2, (n + 1) / 2 + q.deg() / 2);
88-
auto [q0, q1] = q.negx().bisect();
89-
return (
90-
(q0 * qq).x2() + (q1 * qq).x2().mul_xk(1)
91-
).div_xk(2*q0.deg()).mod_xk(n);
83+
auto [q0, q1] = q.bisect();
84+
auto qq = q0 * q0 - (q1 * q1).mul_xk_inplace(1);
85+
inv_inplace(qq, k / 2 - q.deg() / 2, (n + 1) / 2 + q.deg() / 2);
86+
int N = fft::com_size(size(q0.a), size(qq.a));
87+
auto q0f = fft::dft<base>(q0.a, N);
88+
auto q1f = fft::dft<base>(q1.a, N);
89+
auto qqf = fft::dft<base>(qq.a, N);
90+
int M = q0.deg() + (n + 1) / 2;
91+
std::deque<base> A(M), B(M);
92+
q0f.mul(fft::dft<base>(qqf), A, M);
93+
q1f.mul(qqf, B, M);
94+
q.a.resize(n + 1);
95+
for(size_t i = 0; i < n; i += 2) {
96+
q.a[i] = A[q0.deg() + i / 2];
97+
q.a[i + 1] = -B[q0.deg() + i / 2];
98+
}
99+
q.a.pop_back();
100+
q.normalize();
101+
return q;
102+
103+
q = (q0 * qq).x2() - (q1 * qq).x2().mul_xk(1);
104+
return q.div_xk_inplace(2 * q0.deg()).mod_xk_inplace(n);
92105
}
93106
template<typename poly>
94107
poly& inv_inplace(poly& p, size_t n) {
@@ -100,7 +113,7 @@ namespace cp_algo::math::poly::impl {
100113
// Q(-x) = P0(x^2) + xP1(x^2)
101114
auto [q0, q1] = p.bisect(n);
102115

103-
int N = fft::com_size((n + 1) / 2, (n + 1) / 2);
116+
int N = fft::com_size(size(q0.a), (n + 1) / 2);
104117

105118
auto q0f = fft::dft<base>(q0.a, N);
106119
auto q1f = fft::dft<base>(q1.a, N);

verify/poly/linrec_consecutive.test.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// @brief Consecutive Terms of Linear Recursion
22
#define PROBLEM "https://judge.yosupo.jp/problem/consecutive_terms_of_linear_recurrent_sequence"
3+
#pragma GCC optimize("Ofast,unroll-loops")
34
#include "cp-algo/math/poly.hpp"
45
#include <bits/stdc++.h>
56

0 commit comments

Comments
 (0)