// Slow convolution, multiplying two polynomials. // Complexity: O(nu * nv). void conv(const Poly& u, const Poly& v, Poly& w) { int nu = u.size(), nv = v.size(); w.assign(nu + nv - 1, 0.0); for(int i = 0; i < nu; i++) for(int j = 0; j < nv; j++) w[i+j] += u[i] * v[j]; }
// Add b to a or Subs b from a. void sub(Poly& a, const Poly& b) { if(a.size() < b.size()) a.resize(b.size(), 0); for(int i = 0; i < b.size(); ++i) a[i] ^= b[i]; tidy(a); }
Point centerMass( Poly &p ){ Point c( 0 , 0 ) ; for( int i = 0; i < p.size(); i++ ) { c.x += p[i].x ;/// (double)p.size(); c.y += p[i].y ;/// (double)p.size(); } return c / (double) p.size(); }
Poly naiveShiftRight(const Poly& p, int i) { Poly res(p.size() - i); for (unsigned j = i; j < p.size(); j++) { res.setBit(j - i, p.bit(j)); } res.computeDegree(); return res; }
Poly naiveShiftLeft(const Poly& p, int i) { Poly res(p.size() + i); for (unsigned j = 0; j < p.size(); j++) { res.setBit(i + j, p.bit(j)); } res.computeDegree(); return res; }
// Slow convolution, multiplying two polynomials. // Complexity: O(nu * nv). void conv(const Poly& u, const Poly& v, Poly& w) { if(u.empty() || v.empty()) {w.clear(); return;} int nu = u.size(), nv = v.size(); w.assign(nu + nv - 1, 0); for(int i = 0; i < nu; i++) for(int j = 0; j < nv; j++) w[i+j] ^= (u[i] & v[j]); tidy(w); }
vector<p2t::Point*> getP2Tpoints(const Poly &poly) { vector<p2t::Point*> points(poly.size()); for (uint i=0; i<poly.size(); i++) { points[i] = new p2t::Point(poly.vertices[i].x(), poly.vertices[i].y()); } return points; }
void drawPoly(const Poly poly) { sf::VertexArray v(sf::Lines, 2); v[0].color = v[1].color = sf::Color::Red; for (size_t i = 0; i < poly.size(); i++) { v[0].position = poly[i]; v[1].position = poly[(i + 1) % poly.size()]; window.draw(v); } }
Poly integral(Poly const & p) { Poly result; result.reserve(p.size()+1); result.push_back(0); // arbitrary const for(unsigned i = 0; i < p.size(); i++) { result.push_back(p[i]/(i+1)); } return result; }
Poly operator*(Poly p, ll k) { reduce(p); Poly res(p.size()); for (auto i = 0; i < (int)p.size(); i++) { res[i] = (p[i] * k) % MOD; } reduce(res); return res; }
Poly gcd(Poly const &a, Poly const &b, const double tol) { if(a.size() < b.size()) return gcd(b, a); if(b.empty()) return a; if(b.size() == 1) return a; Poly r; divide(a, b, r); return gcd(b, r); }
Poly derivative(Poly const & p) { Poly result; if(p.size() <= 1) return Poly(0); result.reserve(p.size()-1); for(unsigned i = 1; i < p.size(); i++) { result.push_back(i*p[i]); } return result; }
// Slow deconvolution, polynomial dividing. // q returns the quotient, r returns the remainder. void deconv(const Poly& u, const Poly& v, Poly& q, Poly& r) { int n = u.size() - 1; int nv = v.size() - 1; q.assign(n+1, 0.0); r = u; for(int k = n-nv; k >= 0; k--) { q[k] = r[nv+k] / v[nv]; for(int j = nv+k-1; j >= k; j--) r[j] -= q[k] * v[j-k]; } r.resize(nv); }
// Slow deconvolution, polynomial dividing. // q returns the quotient, r returns the remainder. void deconv(const Poly& u, const Poly& v, Poly& q, Poly& r) { int n = u.size() - 1; int nv = v.size() - 1; q.assign(n + 1, 0); r = u; for(int k = n-nv; k >= 0; k--) { q[k] = r[nv+k]; for(int j = nv+k-1; j >= k; j--) r[j] ^= (q[k] & v[j-k]); } r.resize(nv); tidy(q); tidy(r); }
std::vector<cdouble > laguerre(Poly p, const double tol) { std::vector<cdouble > solutions; //std::cout << "p = " << p << " = "; while(p.size() > 1) { double x0 = 0; bool quad_root = false; cdouble sol = laguerre_internal_complex(p, x0, tol, quad_root); //if(abs(sol) > 1) break; Poly dvs; if(quad_root) { dvs.push_back((sol*conj(sol)).real()); dvs.push_back(-(sol + conj(sol)).real()); dvs.push_back(1.0); //std::cout << "(" << dvs << ")"; //solutions.push_back(sol); //solutions.push_back(conj(sol)); } else { //std::cout << sol << std::endl; dvs.push_back(-sol.real()); dvs.push_back(1.0); solutions.push_back(sol); //std::cout << "(" << dvs << ")"; } Poly r; p = divide(p, dvs, r); //std::cout << r << std::endl; } return solutions; }
void simplePolygon( Poly &p ){ Point c = centerMass( p ) ; for( int i = 0; i < p.size(); i++){ p[i].ang = atan2( c.x - p[i].x , c.y - p[i].y ); } sort( p.begin(), p.end() ); }
vector<Poly> triangulate( const Poly &p ){ vector<Poly> res; int n = p.size(); vector<int> l, r; for( int i = 0; i < n; i++){ l.push_back( ( i - 1 + n) % n ); r.push_back( ( i + 1) % n ); } int i = n - 1, cagao = 0; while( res.size() < n - 2 ){ if ( cagao >= n ) return vector<Poly>(); i = r[i]; Poly tmp; tmp.push_back( p[l[i]] ); tmp.push_back( p[i] ); tmp.push_back( p[r[i]] ); if ( can( tmp, p , l[i], i , r[i] ) ){ res.push_back( tmp ); l[ r[i] ] = l[i]; r[ l[i] ] = r[i]; cagao = 0; }else cagao++; } return res; }
// debe ser antihorario vector<Poly> triangulate( const Poly &p ){ vector<Poly> res; int n = p.size(); vector<int> l, r; for( int i = 0; i < n; i++){ l.push_back( ( i - 1 + n) % n ); r.push_back( ( i + 1) % n ); // crea una lista doblemente enlazada } int i = n - 1, cagao = 0; while( res.size() < n - 2 ){ if ( cagao >= n ) return vector<Poly>(); i = r[i]; // avanza tipo un i++ Poly tmp; tmp.push_back( p[l[i]] ); tmp.push_back( p[i] ); tmp.push_back( p[r[i]] ); // crea un triangulo if ( can( tmp, p , l[i], i , r[i] ) ){ // checa si sirve res.push_back( tmp ); // guardamos la solucion l[ r[i] ] = l[i]; r[ l[i] ] = r[i]; // con estas dos operaciones en O(1) borramos el punto del "medio" del triangulo cagao = 0; // no fallo }else cagao++; // se fue al carajo } return res; }
Poly divide(Poly const &a, Poly const &b, Poly &r) { Poly c; r = a; // remainder assert(b.size() > 0); const unsigned k = a.degree(); const unsigned l = b.degree(); c.resize(k, 0.); for(unsigned i = k; i >= l; i--) { assert(i >= 0); double ci = r.back()/b.back(); c[i-l] += ci; Poly bb = ci*b; //std::cout << ci <<"*(" << b.shifted(i-l) << ") = " // << bb.shifted(i-l) << " r= " << r << std::endl; r -= bb.shifted(i-l); r.pop_back(); } //std::cout << "r= " << r << std::endl; r.normalize(); c.normalize(); return c; }
i64 Count(int L, int P, Poly &fab) { i64 r = 0; for(int i=0; i<fab.size(); i++) r += gpow[i % (P-1)] < L ? fab[i] : 0; return r; }
void put(const Poly& p) { int N = p.size() - 1; cout << N; for(int i = N; i >= 0; --i) cout << ' ' << p[i]; puts(""); }
// nearest connection point indices of this and other poly // if poly is not closed, only test first and last point void Poly::nearestIndices(const Poly &p2, int &thisindex, int &otherindex) const { double mindist = INFTY; for (uint i = 0; i < size(); i++) { if (!closed && i != 0 && i != size()-1) continue; for (uint j = 0; j < p2.size(); j++) { if (!p2.closed && j != 0 && j != p2.size()-1) continue; double d = vertices[i].squared_distance(p2.vertices[j]); if (d < mindist) { mindist = d; thisindex = i; otherindex= j; } } } }
cdouble laguerre_internal_complex(Poly const & p, double x0, double tol, bool & quad_root) { cdouble a = 2*tol; cdouble xk = x0; double n = p.degree(); quad_root = false; const unsigned shuffle_rate = 10; // static double shuffle[] = {0, 0.5, 0.25, 0.75, 0.125, 0.375, 0.625, 0.875, 1.0}; unsigned shuffle_counter = 0; while(std::norm(a) > (tol*tol)) { //std::cout << "xk = " << xk << std::endl; cdouble b = p.back(); cdouble d = 0, f = 0; double err = abs(b); double abx = abs(xk); for(int j = p.size()-2; j >= 0; j--) { f = xk*f + d; d = xk*d + b; b = xk*b + p[j]; err = abs(b) + abx*err; } err *= 1e-7; // magic epsilon for convergence, should be computed from tol cdouble px = b; if(abs(b) < err) return xk; //if(std::norm(px) < tol*tol) // return xk; cdouble G = d / px; cdouble H = G*G - f / px; //std::cout << "G = " << G << "H = " << H; cdouble radicand = (n - 1)*(n*H-G*G); //assert(radicand.real() > 0); if(radicand.real() < 0) quad_root = true; //std::cout << "radicand = " << radicand << std::endl; if(G.real() < 0) // here we try to maximise the denominator avoiding cancellation a = - sqrt(radicand); else a = sqrt(radicand); //std::cout << "a = " << a << std::endl; a = n / (a + G); //std::cout << "a = " << a << std::endl; if(shuffle_counter % shuffle_rate == 0) { //a *= shuffle[shuffle_counter / shuffle_rate]; } xk -= a; shuffle_counter++; if(shuffle_counter >= 90) break; } //std::cout << "xk = " << xk << std::endl; return xk; }
Poly operator%(Poly p, Poly q) { reduce(p); reduce(q); if (p.size() < q.size()) { return p; } if (!is_monic(q)) { return p % monic(q); } Poly s_q = shift(q, p.size() - q.size()); Poly res = (p - p.back() * s_q); reduce(res); return res % q; }
double area( Poly &p ){ double res = 0.0; int n = p.size(); for( int i = 0; i < n; i++){ res += p[ i ] % p[ ( i + 1 ) % n ]; } return fabs(res / 2.0 ); }
// triangular un poligono en O(2*n^2) devuelve un vector de triangulos bool can( const Poly &t, const Poly &p, int i , int j , int k ){ if(ccw(t[0], t[1], t[2]) <= 0) return false; for(int l = 0; l < p.size(); l++){ if(l != i && l != j && l != k) if( inTriang(t, p[l])) return false; } return true; }
// triangular un poligono en O(2*n^2) devuelve un vector de triangulos bool can( const Poly &t, const Poly &p, int i , int j , int k ){ if(ccw(t[0], t[1], t[2]) <= 0) return false; // si esta tipo para afuera cago ps for(int l = 0; l < p.size(); l++){ // revisa que ningun punto este dentro del triangulo que formamos if(l != i && l != j && l != k) if( inTriang(t, p[l])) return false; } return true; }
Poly compose(Poly const & a, Poly const & b) { Poly result; for(unsigned i = a.size(); i > 0; i--) { result = Poly(a[i-1]) + result * b; } return result; }
Poly operator+(Poly p, Poly q) { reduce(p); reduce(q); if (p.size() < q.size()) { return q + p; } else { for (auto i = 0; i < (int)q.size(); i++) { p[i] += q[i]; p[i] %= MOD; } } reduce(p); return p; }
Poly operator*(Poly p, Poly q) { reduce(p); reduce(q); Poly res(p.size() + q.size() - 1, 0); for (auto i = 0; i < (int)res.size(); i++) { for (auto j = 0; j <= i; j++) { if (j < (int)p.size() && i - j < (int)q.size()) { res[i] += (p[j] * q[i - j]) % MOD; res[i] %= MOD; } } } reduce(res); return res; }