template/zhongzihao/polynomial

// 多项式模板 

#include<bits/stdc++.h>
#include"fft.cpp"

class poly{
private:
	constexpr const static double eps = 1e-9;
	
	double *a;
	int length, size;
	
	void apply(int size){
		if (!size) return;
		a = new double [size]();
		this -> size = size;
	}
	
	void resize(int size){
		if (!size) return;
		double *aux = a;
		a = new double [size]();
		memcpy(a, aux, sizeof(double) * (length + 1));
		if (this -> size) delete [] aux;
		this -> size = size;
	}
	
	void initpoly(const poly &p, int length){
		clear();
		apply(length + 2 << 1);
		memcpy(a, p.a, sizeof(double) * (std::min(length, p.length) + 1));
		this -> length = length;
	}
	
public:
	poly():a(nullptr), length(-1), size(0){}
	poly(int length):a(nullptr), length(length){apply(length + 2 << 1);}
	poly(const poly &p):a(nullptr){initpoly(p, p.length);}
	poly(const poly &p, int length):a(nullptr){initpoly(p, length);}
	~poly(){clear();}
	void clear(){delete [] a; a = nullptr; size = length = 0;}
	double &operator [](int n){return a[n];}
	int getlength(){return length;}
	
	// 将多项式的次数设为 length,如果次数减小则截断多余部分 
	void setlength(int length){
		if (length >= size) resize(length + 2 << 1);
		if (length >= this -> length){
			this -> length = length;
			return;
		}
		memset(a + length + 1, 0, sizeof(double) * (this -> length - length));
		this -> length = length;
	}
	
	poly &operator = (const poly &p){
		if (&p != this) initpoly(p, p.length);
		return *this;
	}
	
	// 相当于乘以 x ^ dis
	poly operator << (const int &dis)const{
		poly ret(length + dis);
		memcpy(ret.a + dis, a, sizeof(double) * (length + 1));
		return ret;
	}
	
	// 相当于除以 x ^ dis
	poly operator >> (const int &dis)const{
		if (dis > length) return poly(-1);
		poly ret(length - dis);
		memcpy(ret.a, a + dis, sizeof(double) * (ret.length + 1));
		return ret;
	}
	
	double value(double x){
		double now = 1, ret = 0;
		for (int i = 0; i <= length; ++ i){
			ret += a[i] * now;
			now *= x;
		}
		return ret;
	}
	
	poly operator + (const poly &p)const{
		if (!~length) return p;
		if (!~p.length) return *this;
		poly ret(*this, std::max(length, p.length));
		for (int i = 0; i <= p.length; ++ i){
			ret.a[i] += p.a[i];
		}
		for ( ; ~ret.length && std::abs(ret.a[ret.length]) < eps; -- ret.length)
			;
		return ret;
	}
	
	poly operator - (const poly &p)const{
		if (!~length) return p;
		if (!~p.length) return *this;
		poly ret(*this, std::max(length, p.length));
		for (int i = 0; i <= p.length; ++ i){
			ret.a[i] -= p.a[i];
		}
		for ( ; ~ret.length && std::abs(ret.a[ret.length]) < eps; -- ret.length)
			;
		return ret;
	}
	
	poly operator - ()const{
		poly ret(length);
		for (int i = 0; i <= length; ++ i){
			ret.a[i] = -a[i];
		}
		return ret;
	}
	
	poly operator * (const poly &p)const{
		if (!~length || !~p.length) return poly(-1);
		int n = length + p.length;
		int lengthret = 1;
		for ( ; lengthret <= n; lengthret <<= 1)
			;
		std::complex <double> *aux = new std::complex <double> [lengthret];
		std::complex <double> *aux1 = new std::complex <double> [lengthret];
		for (int i = 0; i < lengthret; ++ i){
			aux[i] = i > length ? 0 : a[i];
			aux1[i] = i > p.length ? 0 : p.a[i];
		}
		FFT(aux, lengthret, 1);
		FFT(aux1, lengthret, 1);
		for (int i = 0; i < lengthret; ++ i){
			aux[i] *= aux1[i];
		}
		FFT(aux, lengthret, -1);
		poly ret(n);
		for (int i = 0; i <= n; ++ i){
			ret.a[i] = aux[i].real();
		}
		delete [] aux;
		delete [] aux1;
		return ret;
	}
	
	poly operator * (const double &p)const{
		poly ret(length);
		for (int i = 0; i <= length; ++ i){
			ret.a[i] = a[i] * p;
		}
		return ret;
	}
	
	friend poly operator * (const double &q, const poly &p){return p * q;}
	poly &operator += (const poly &p){*this = *this + p; return *this;}
	poly &operator -= (const poly &p){*this = *this - p; return *this;}
	poly &operator *= (const poly &p){*this = *this * p; return *this;}
	poly &operator *= (const double &p){*this = *this * p; return *this;}
	
	poly inv(int n)const{
		if (std::abs(a[0]) < eps) assert(("Invalid polynomial inv!", 0));
		poly ret(1);
		ret.a[0] = 1 / a[0];
		for (int nowprecision = 0; nowprecision < n; ){
			nowprecision = nowprecision << 1 | 1;
			poly aux(*this, nowprecision), aux1(ret);
			ret *= ret;
			ret.setlength(nowprecision);
			aux *= ret, aux.setlength(nowprecision);
			ret = 2 * aux1 - aux;
		}
		ret.setlength(n - 1);
		return ret;
	}
	
	poly der()const{
		if (!~length) return poly(-1);
		poly ret(length - 1);
		for (int i = 0; i < length; ++ i){
			ret.a[i] = a[i + 1] * (i + 1);
		}
		return ret;
	}
	
	poly integral()const{
		poly ret(length + 1);
		for (int i = 1; i <= length + 1; ++ i){
			ret.a[i] = a[i - 1] / i;
		}
		return ret;
	}
	
	poly operator / (const poly &p)const{
		if (!~p.length) assert(("Invalid polynomial division!", 0));
		if (p.length > length) return poly(-1);
		poly a(*this), b(p);
		std::reverse(a.a, a.a + a.length + 1);
		std::reverse(b.a, b.a + b.length + 1);
		poly ret(p.inv(length - p.length + 1));
		ret *= *this;
		ret.setlength(length - p.length);
		std::reverse(ret.a, ret.a + ret.length + 1);
		return ret;
	}
	
	poly operator % (const poly &p)const{return *this - *this / p * p;}
	poly &operator /= (const poly &p){*this = *this / p; return *this;}
	poly &operator %= (const poly &p){*this = *this % p; return *this;}
	
	poly log(int n)const{
		if (std::abs(a[0] - 1) >= eps) assert(("Invalid polynomial log!", 0));
		poly aux(*this, n - 1);
		poly ret(aux.der() * aux.inv(n));
		ret.setlength(n - 2);
		return ret.integral();
	}
	
	poly exp(int n)const{
		if (std::abs(a[0]) >= eps) assert(("Invalid polynomial exp!", 0));
		poly ret(0);
		ret.a[0] = 1;
		poly unit(ret);
		for (int nowprecision = 0; nowprecision < n; ){
			nowprecision = nowprecision << 1 | 1;
			poly aux(*this, nowprecision);
			ret *= unit - ret.log(nowprecision + 1) + aux;
			ret.setlength(nowprecision);
		}
		ret.setlength(n - 1);
		return ret;
	}
	
	template <typename T>
	poly power(T exp)const{
		poly ret(0), aux(*this);
		ret.a[0] = 1;
		for ( ; exp; exp >>= 1){
			if (exp & 1){
				ret *= aux;
			}
			aux *= aux;
		}
		return ret;
	}
};

int main(){
	return 0;
}