cai_lw's competitive programming library
 
Loading...
Searching...
No Matches
poly.hpp
1#pragma once
2
3#include <vector>
4#include <utility>
5#include "cplib/conv/conv.hpp"
6
7namespace cplib {
8
9template<typename F>
10struct Polynomial {
11 Polynomial() {}
12
13 Polynomial(int c) : coef({F(c)}) {}
14
15 Polynomial(const std::vector<F> &_coef) : coef(_coef) {}
16
17 Polynomial(std::vector<F> &&_coef) : coef(std::move(_coef)) {}
18
19 size_type size() const {
20 return coef.size();
21 }
22
23 void trim_leading_zeros() {
24 while (!coef.empty() && coef.back() == F(0)) {
25 coef.pop_back();
26 }
27 }
28
29 void resize(size_type new_size) {
30 coef.resize(new_size, F(0));
31 }
32
33 void operator+=(const Polynomial &other) {
34 for (size_type i = 0; i < other.size(); i++) {
35 if (i < coef.size()) {
36 coef[i] += other.coef[i];
37 } else {
38 coef.push_back(other.coef[i]);
39 }
40 }
41 }
42
43 Polynomial operator+(const Polynomial &other) const {
44 Polynomial ret = *this;
45 ret += other;
46 return ret;
47 }
48
49 void operator-=(const Polynomial &other) {
50 for (size_type i = 0; i < other.size(); i++) {
51 if (i < coef.size()) {
52 coef[i] -= other.coef[i];
53 } else {
54 coef.push_back(-other.coef[i]);
55 }
56 }
57 }
58
59 Polynomial operator-(const Polynomial &other) const {
60 Polynomial ret = *this;
61 ret -= other;
62 return ret;
63 }
64
65 void negate_inplace() {
66 for (F &c : coef) {
67 c = -c;
68 }
69 }
70
71 Polynomial opreator-() const {
72 Polynomial ret = *this;
73 ret.negate_inplace();
74 return ret;
75 }
76
77 void operator*=(const Polynomial &other) {
78 convolve_inplace(coef, other.coef);
79 }
80
81 Polynomial operator*(const Polynomial &other) const {
82 Polynomial ret = *this;
83 ret *= other;
84 return ret;
85 }
86
87 // f(x)g(x) = 1 (mod x^N)
88 Polynomial fps_inverse(size_type deg) const {
89 Polynomial ret;
90 ret.coef.reserve(deg);
91 ret.coef.emplace_back(F(1) / coef[0]);
92 size_type ret_size = 1;
93 // Newton's method: g:=g(2-f*g)
94 while (ret_size < deg) {
95 Polynomial prod(vector<F>(coef.begin(), coef.begin() + std::min(ret_size, size())));
96 prod *= ret;
97 prod.negate_inplace();
98 prod.coef[0] += F(2);
99 ret *= prod;
100 ret_size = std::min(ret_size * 2, deg);
101 ret.resize(ret_size);
102 }
103 return ret;
104 }
105
106 Polynomial rev() const {
107 Polynomial ret = *this;
108 reverse(ret.coef.begin(), ret.coef.end());
109 return ret;
110 }
111
112 // f(x) = g(x)q(x) + r(x) deg(r) < deg(g)
113 std::pair<Polynomial, Polynomial> div_mod(const Polynomial &other) const {
114 if (size() < other.size()) {
115 return {{}, *this};
116 }
117 size_type quot_size = size() - other.size() + 1;
118 Polynomial quot;
119 if (quot_size > 1) {
120 quot = this->rev() * other.rev().fps_inverse(quot_size - 1);
121 quot.resize(quot_size);
122 reverse(quot.coef.begin(), quot.coef.end());
123 quot.coef[0] = F(0);
124 } else {
125 quot.coef.emplace_back(0);
126 }
127 Polynomial rem = quot * other;
128 rem -= *this;
129 rem.negate_inplace();
130 quot.coef[0] = rem.coef[other.size() - 1] / other.coef.back();
131 for (size_type i = 0; i < other.size(); i++)
132 rem.coef[i] -= quot.coef[0] * other.coef[i];
133 rem.trim_leading_zeros();
134 return {quot, rem};
135 }
136
137 Polynomial operator/(const Polynomial &other) const {
138 return div_mod(other).first;
139 }
140
141 void operator/=(const Polynomial &other) {
142 *this = *this / other;
143 }
144
145 Polynomial operator%(const Polynomial &other) const {
146 return div_mod(other).second;
147 }
148
149 void operator%=(const Polynomial &other) {
150 *this = *this % other;
151 }
152
153private:
154 std::vector<F> coef;
155 using size_type = std::vector<F>::size_type;
156};
157
158} // namespace cplib
void convolve_inplace(std::vector< T > &a, const std::vector< T > &b)
In-place convolution where one array is modified.
Definition: conv.hpp:85
Definition: poly.hpp:10