多项式板子
缺开方,多点求值。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int p=998244353,G=3;
const int N=1e6+5;
int rev[N];
int qpow(int a,int b) {
int ans=1;
while(b) {
if(b&1) ans=ans*a%p;
a=a*a%p;
b>>=1;
}
return ans;
}
void change(vector<int> &x,int len) {
for(int i=0; i<len; i++) {
rev[i]=rev[i>>1]>>1;
if(i&1) rev[i]|=(len>>1);
}
for(int i=0; i<len; i++) if(rev[i]>i) swap(x[i],x[rev[i]]);
}
void ntt(vector<int> &x,int len,int flag) {
change(x,len);
for(int i=1; i<len; i<<=1) {
int gn=qpow(flag==1?G:qpow(G,p-2),(p-1)/(i<<1));
for(int j=0; j<len; j+=(i<<1)) {
int g=1;
for(int k=j; k<j+i; k++) {
int l=x[k],r=g*x[k+i]%p;
x[k]=(l+r)%p,x[k+i]=(l-r+p)%p;
g=g*gn%p;
}
}
}
if(flag==-1) {
int inv=qpow(len,p-2);
for(int i=0; i<len; i++) x[i]=x[i]*inv%p;
}
}
struct poly {
mutable vector<int> x;
void read(int n) {x.resize(n);for(int i=0; i<n; i++) cin>>x[i];}
void write(int n=-1) {if(!~n) n=x.size();for(int i=0; i<n; i++) cout<<x[i]<<" ";cout<<"\n";}
poly operator+(const poly &o) const {
poly a=*this,b=o;
int len=max(a.x.size(),b.x.size());
a.x.resize(len),b.x.resize(len);
for(int i=0; i<len; i++) a.x[i]=(a.x[i]+b.x[i])%p;
return a;
}
poly operator-(const poly &o) const {
poly a=*this,b=o;
int len=max(a.x.size(),b.x.size());
a.x.resize(len),b.x.resize(len);
for(int i=0; i<len; i++) a.x[i]=(a.x[i]-b.x[i]+p)%p;
return a;
}
poly operator*(const poly &o) const {
poly a=*this,b=o;
int len=1,tmp=a.x.size()+b.x.size()-1;
while(len<tmp) len<<=1;
a.x.resize(len),b.x.resize(len);
ntt(a.x,len,1),ntt(b.x,len,1);
for(int i=0; i<len; i++) a.x[i]=a.x[i]*b.x[i]%p;
ntt(a.x,len,-1);
a.x.resize(tmp);
return a;
}
poly operator*(const int &o) const {
poly a=*this;
for(int i=0; i<a.x.size(); i++) a.x[i]=(a.x[i]*o%p+p)%p;
return a;
}
poly inv() {
poly a=*this,b,s,t;
int n=a.x.size();
b.x.resize(n<<1);
b.x[0]=qpow(a.x[0]%p,p-2);
int len=2;
while(len<2*a.x.size()) {
s.x.resize(len),t.x.resize(len);
for(int i=0; i<len; i++) s.x[i]=a.x[i];
for(int i=0; i<len; i++) t.x[i]=b.x[i];
for(int i=0; i<len; i++) b.x[i]=2*t.x[i]%p;
s=s*t*t;
for(int i=0; i<len; i++) b.x[i]=(b.x[i]-s.x[i]+p)%p;
len<<=1;
}
b.x.resize(n);
return b;
}
poly operator/(const poly &o) const {
poly a=*this,b=o;
int n=a.x.size(),m=b.x.size();
reverse(a.x.begin(),a.x.end());
reverse(b.x.begin(),b.x.end());
b.x.resize(n-m+2);
a=a*b.inv();
a.x.resize(n-m+1);
reverse(a.x.begin(),a.x.end());
return a;
}
poly operator%(const poly &o) const {
poly a=*this,b=o;
poly c=a-a/b*b;
c.x.resize(b.x.size()-1);
return c;
}
poly dao() {
poly a=*this;
for(int i=0; i<a.x.size()-1; i++) a.x[i]=a.x[i+1]*(i+1)%p;
a.x.pop_back();
return a;
}
poly ji() {
poly a=*this;a.x.push_back(0);
for(int i=a.x.size()-1; i>=1; i--) a.x[i]=a.x[i-1]*qpow(i,p-2)%p;
a.x[0]=0;
return a;
}
poly ln() {
poly a=*this;
int n=a.x.size();
a=(a.dao()*a.inv()).ji();
a.x.resize(n);
return a;
}
poly exp() {
poly a=*this,b,s,t;
int n=a.x.size();
b.x.resize(n<<1);
b.x[0]=1;
int len=2;
while(len<(n<<1)) {
s.x.resize(len),t.x.resize(len);
for(int i=0; i<len; i++) s.x[i]=a.x[i];
for(int i=0; i<len; i++) t.x[i]=b.x[i];
s=t.ln()*(-1)+s;
s.x[0]=(s.x[0]+1)%p;
s=s*t;
for(int i=0; i<len; i++) b.x[i]=s.x[i];
len<<=1;
}
b.x.resize(n);
return b;
}
};
__EOF__

本文作者:System_Error
本文链接:https://www.cnblogs.com/System-Error/p/18698319.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
本文链接:https://www.cnblogs.com/System-Error/p/18698319.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
« 上一篇: 240117 lxl省选模拟
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术