推销一下基于继承的多项式封装,好多函数可以直接用vector的,不用再次封装了,省事很多
另外()运算符太赞了,虽然时间是resize()的\(4\)倍,但是很好用!!,再也不用费力计算多项式的大小了!!!
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
const int N = 4e5+10;
int rev[N];
ll qpow(ll a, ll b){
ll ret = 1;
for(; b ; b >>= 1){
if(b & 1) ret = ret *a % MOD;
a = a * a % MOD;
}
return ret;
}
ll ginv(ll x){
return qpow(x, MOD - 2);
}
ll add(ll x, ll y){
x += y;
if(x >= MOD) return x - MOD;
return x;
}
ll sub(ll x, ll y){
x -= y;
if(x < 0) return x + MOD;
return x;
}
ll w[N];
int preNTT(int len){
int deg = 1;
while(deg < len) deg *= 2;
for(int i = 0; i < deg; ++i)
rev[i] = (rev[i >> 1] >> 1) | (i & 1 ? deg / 2 : 0);
w[0] = 1;
w[1] = qpow(3, (MOD - 1) / deg);
for(int i = 2; i < deg; ++i) w[i] = w[i - 1] * w[1]% MOD;
return deg;
}
struct poly : vector<ll>{
using vector ::vector;
using vector :: operator [];
void cksize(int x){
if(size() < x) resize(x);
}
ll& operator ()(int x){
cksize(x + 1);
return this->operator[](x);
}
friend poly diff(poly f){
for(int i = 0; i + 1 < f.size(); ++i){
f[i] = f[i + 1] * (i + 1) % MOD;
}
f.pop_back();
return f;
}
friend poly inte(poly f){
for(int i = int(f.size()) - 1; i >= 1; --i){
f[i] = f[i - 1] * ginv(i) % MOD;
}
f[0] = 0;
return f;
}
void makemod(){
for(auto & it : (*this)){
it = (it % MOD+ MOD) % MOD;
}
}
friend void NTT(poly &f, int deg, int opt){
f.resize(deg);
// f.ckmod();
for(int i = 0; i < deg; ++i){
if(i < rev[i]) std::swap(f[i], f[rev[i]]);
}
for(int h = 2, m = 1, t = deg / 2; h <= deg; h *= 2, m *= 2, t /= 2){
for(int l = 0; l < deg; l += h){
for(int i = l, j = 0; i < l + m; ++j,++i){
ll x = f[i], y = w[t * j] * f[i + m] % MOD;
f[i] = add(x, y);
f[i + m] = sub(x, y);
}
}
}
f.makemod();
if(opt == -1){
reverse(f.begin() + 1, f.end());
ll iv = ginv(deg);
for(auto &it : f){
it = it * iv % MOD;
}
}
}
friend poly dmul(poly f,const poly& g){
f.cksize(g.size());
for(int i = 0; i < g.size(); ++i){
f[i] = f[i] * g[i] % MOD;
}
return f;
}
friend poly operator - (poly f, const poly& g){
f.cksize(g.size());
for(int i = 0; i < g.size(); ++i){
f[i] = (f[i] - g[i] + MOD) % MOD;
}
return f;
}
friend poly operator *(poly f, poly g){
if(f.empty()|| g.empty()) return {};
int len = f.size() + g.size() - 1;
int deg = preNTT(len);
NTT(f, deg, 1);
NTT(g, deg, 1);
f = dmul(std::move(f), g);
NTT(f, deg, -1);
f.resize(len);
return f;
}
friend poly pinv(const poly& f){
if(f.empty()) return {};
poly ret;
ret(0) = ginv(f[0]);
poly a;
for(int len = 2; len < (2 * f.size()); len *= 2){
a.assign(f.begin(), f.begin() + min(len, (int)f.size()));
ret.resize(min(len, (int)(f.size())));
int deg = preNTT(a.size() + ret.size() - 1);
NTT(ret, deg, 1);
NTT(a, deg, 1);
for(int i = 0; i < deg; ++i)
ret[i] = (2 - a[i] * ret[i] % MOD) * ret[i] % MOD;
ret.makemod();
NTT(ret, deg, -1);
ret.resize(len);
}
ret.resize(f.size());
return ret;
}
friend poly sqrt(const poly& f){
poly res;
res(0) = 1;
poly a;
ll iv2 = ginv(2);
for(int len = 2; len < 2 * f.size(); len *= 2){
res.resize(len);
a.assign(f.begin(), f.begin() + min(len, (int)f.size()));
a = a * pinv(res);
for(int i = 0; i < len; ++i) res[i] = (res[i] + a[i]) * iv2 % MOD;
}
res.resize(f.size());
return res;
}
friend poly ln(const poly& f){
poly res = inte(diff(f) * pinv(f));
res.resize(f.size());
return res;
}
friend poly exp(const poly& f){
poly ret;
ret(0) = 1;
poly a, b;
for(int len = 2; len < f.size() * 2; len *= 2){
ret.resize(len);
a = ln(ret);
b.assign(f.begin(), f.begin() + min(len, (int)f.size()));
b = b - a;
b[0] ++ ;
ret = ret * b;
ret.resize(len);
}
ret.resize(f.size());
return ret;
}
}f;
int read(){
int x = 0;
char ch = getchar();
while(!isdigit(ch)) ch = getchar();
while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
return x;
}
int main(){
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int n;
cin >> n;
f.resize(n);
for(int i = 0; i < n; ++i){
cin >> f[i];
}
f = exp(f);
for(int i = 0; i < n; ++i){
cout << f[i] <<" ";
}
cout <<endl;
return 0;
}
标签:封装,int,多项式,ll,poly,return,MOD,deg
From: https://www.cnblogs.com/cdsidi/p/17024940.html