技术有限,常数较大,但是方便(

重载了加减乘,写了求逆元、求ln,求exp、求sqrt、求幂(普通)。

#include <vector>
#include <stack>
using namespace std;

namespace polynomial {
typedef long long ll;
const int P = 998244353;
const int g = 3, gi = 332748118;
int lim, bit;
vector<int> r;
struct poly : vector<ll> {
poly() {};
poly(ll a)
{
resize(1);
(*this)[0] = (a%P+P)%P;
}
poly& modx(int n)
{
resize(n);
return *this;
}
};
inline ll qpow(ll a, ll b, ll p = P)
{
ll ans = 1;
for(; b; b >>= 1, a = a*a%p)
if(b&1) ans = ans*a%p;
return ans;
}
inline void dnt_prework(int n)
{
lim = 1, bit = 0;
while(lim < n+1) lim <<= 1, bit++;
r.resize(lim);
for(int i = 0; i < lim; i++)
r[i] = (r[i>>1]>>1) | ((i&1)<<(bit-1));
}
inline void builtin_change(poly &a, bool type)
{
for(int i = 0; i < lim; i++)
if(i < r[i]) swap(a[i], a[r[i]]);
for(int mid = 1; mid < lim; mid <<= 1)
{
ll wn = qpow(type?g:gi, (P-1)/(mid<<1));
for(int j = 0, k = 0; j < lim; j += (mid<<1), k = j)
{
for(ll w = 1; k < j+mid; k++, w = w*wn%P)
{
ll x = a[k], y = w*a[k+mid]%P;
a[k] = (x+y)%P, a[k+mid] = (x-y+P)%P;
}
}
}
}
inline void dnt(poly &a)
{
a.resize(lim);
builtin_change(a, true);
}
inline void idnt(poly &a)
{
a.resize(lim);
builtin_change(a, false);
ll liminv = qpow(lim, P-2);
for(int i = 0; i < lim; i++)
a[i] = a[i]*liminv%P;
}

inline poly operator + (const poly &a, const poly &b)
{
poly c = a;
if(a.size() < b.size()) c.resize(b.size());
for(int i = 0; i < b.size(); i++)
c[i] = (c[i]+b[i])%P;
return c;
}
inline poly operator - (const poly &a, const poly &b)
{
poly c = a;
if(a.size() < b.size()) c.resize(b.size());
for(int i = 0; i < b.size(); i++)
c[i] = (c[i]-b[i]+P)%P;
return c;
}
poly operator * (poly a, poly b)
{
int len = a.size()+b.size()-2;
dnt_prework(len);
poly ans; ans.resize(lim+1);
dnt(a); dnt(b);
for(int i = 0; i < lim; i++)
ans[i] = a[i]*b[i]%P;
idnt(ans);
ans.resize(len+1);
return ans;
}
inline poly operator * (poly a, const ll &k)
{
for(int i = 0; i < a.size(); i++)
a[i] = a[i]*k%P;
return a;
}

inline poly derivation(const poly &a)
{
poly b; b.resize(a.size()-1);
for(int i = 1; i < a.size(); i++)
b[i-1] = a[i]*i%P;
return b;
}
inline poly integral(const poly &a)
{
poly b; b.resize(a.size()+1);
for(int i = a.size()-1; i >= 1; i--)
b[i] = a[i-1]*qpow(i, P-2)%P;
return b;
}
inline poly inv(const poly &a)
{
stack<int> st;
int n = a.size();
while(n > 1) st.push(n), n = (n+1)/2;
poly b = qpow(a[0], P-2);
while(st.size())
{
n = st.top(); st.pop();
poly c = a; c.modx(n); b.modx(n);
b = (b*2-((c*b).modx(n)*b).modx(n)).modx(n);
}
return b.modx(a.size());
}
inline poly ln(const poly &a)
{
poly b, tmp;
b = integral((derivation(a)*inv(a)));
return b.modx(a.size());
}
inline poly sqrt(const poly &a)
{
stack<int> st;
int n = a.size();
while(n > 1) st.push(n), n = (n+1)/2;
poly b = qpow(a[0], P-2);
while(st.size())
{
n = st.top(); st.pop();
poly c = a;
c.modx(n); b.modx(n);
b = ((c+(b*b).modx(n))*inv(b*2)).modx(n);
}
return b.modx(a.size());
}
inline poly exp(const poly &a)
{
stack<int> st;
int n = a.size();
while(n > 1) st.push(n), n = (n+1)/2;
poly b = 1;
while(st.size())
{
n = st.top(); st.pop();
poly c = a;
b.modx(n); c.modx(n);
b = ((1-ln(b)+c)*b).modx(n);
}
return b.modx(a.size());
}
inline poly pow(const poly &a, const ll &k)
{
return exp(k*ln(a));
}
}
using namespace polynomial;