题意:如其名……
思路:
多项式的关键在于:用模的次数降次。
它的复杂度跟模数的次幂有关。
所以可以考虑对模数分治。参考
若多项式只有一项,直接求常数项的逆元(这也是判别多想式是否存在逆元的条件)。
设已知
则
所以
两边平方得:
因为把平方看成两个多项式相乘
而模为,即它的最小系数非负次数为。
当然分成的与必有一个小于。
因此两边同乘,根据得:
code:
ouo
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const ll mod=998244353;
ll ksm(ll a,ll b) {ll res=1;for(;b;b>>=1,a=a*a%mod)if(b&1)res=res*a%mod;return res;}
//ll ksm(ll x,ll y) {ll res=1;for(;y;y>>=1,x=x*x%mod)if(y&1)res=res*x%mod;return res;}
ll f[N],a[N],c[N],inv3,gen[2][N];
int up,l,rev[N],n;
void NTT(ll *a,int op) {
for(int i=0;i<up;i++) {
if(rev[i]>i)swap(a[i],a[rev[i]]);
}
for(int mid=1;mid<up;mid<<=1) {
int len=mid<<1;ll w1=gen[op][len];
// printf("!(%d,%d) %lld (%lld,%lld)\n",op,len,(w1+mod)%mod,ksm(3,(mod-1)/len),ksm(inv3,(mod-1)/len));
for(int l=0;l<up;l+=len) {
ll W=1;
for(int i=0;i<mid;i++,W=W*w1%mod) {
int p=l+i,q=p+mid;
ll x=a[p],y=W*a[q];
a[p]=(x+y)%mod;a[q]=(x-y)%mod;
}
}
}
}
void gt_up(int len) {
up=1,l=0;
while(up<len) {up<<=1,l++;}
for(int i=1;i<up;i++) {rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));}
}
ll ans[N];
void solve(int dep,ll *b) { //b为该层(%x^{dep})得到的结果
if(dep==1) {b[0]=ksm(f[0],mod-2);return;}
solve((dep+1)>>1,b);
gt_up(dep<<1);
// printf("dep=%d up=%d~~\n",dep,up);
for(int i=0;i<dep;i++)a[i]=f[i];for(int i=dep;i<up;i++)a[i]=0;
NTT(b,0);NTT(a,0);
// printf("A:\n");for(int i=0;i<up;i++)printf("%d ",(a[i]%mod+mod)%mod);puts("");
// printf("B:\n");for(int i=0;i<up;i++)printf("%d ",(b[i]%mod+mod)%mod);puts("");
for(int i=0;i<up;i++) {c[i]=(2-a[i]*b[i]%mod)*b[i]%mod;}
NTT(c,1);
ll i_up=ksm(up,mod-2);
for(int i=0;i<dep;i++) {b[i]=c[i]*i_up%mod;} for(int i=dep;i<up;i++)b[i]=0;
// printf("S:\n");for(int i=0;i<up;i++)printf("%d ",(b[i]%mod+mod)%mod);puts("");
}
void gt_gen() {
inv3=ksm(3,mod-2);
gt_up(n<<1);
// printf("!%d\n",up);
gen[0][up]=ksm(3,(mod-1)/up);gen[1][up]=ksm(inv3,(mod-1)/up);
for(int i=up;i;i>>=1) {
// printf("i=%d %lld(%lld),%lld(%lld)\n",i,gen[0][i],ksm(3,(mod-1)/i),gen[1][i],ksm(inv3,(mod-1)/i));
gen[0][i>>1]=gen[0][i]*gen[0][i]%mod;
gen[1][i>>1]=gen[1][i]*gen[1][i]%mod;
}
}
int main() {
scanf("%d",&n);
gt_gen();
for(int i=0;i<n;i++) {scanf("%lld",&f[i]);}
solve(n,ans);
for(int i=0;i<n;i++) {printf("%lld ",(ans[i]+mod)%mod);}
return 0;
}
ps.还有柯爱的
code:板套板,不会mtt,注意拆的系数最好,我随便用的它精度就G了。
点击查看代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double db;
const db pi=acos(-1.0);
const int N=1e6+5;
const ll mod=1e9+7;
ll ksm(ll a,ll b) {ll res=1;for(;b;b>>=1,a=a*a%mod)if(b&1)res=res*a%mod;return res;}
ll f[N],a[N],c[N],bas=sqrt(mod);
int up,l,rev[N],n;
struct cop {
db img,rl;
friend inline cop operator*(cop u,cop v) {return (cop){u.rl*v.img+u.img*v.rl,u.rl*v.rl-u.img*v.img};}
friend inline cop operator+(cop u,cop v) {return (cop){u.img+v.img,u.rl+v.rl};}
friend inline cop operator-(cop u,cop v) {return (cop){u.img-v.img,u.rl-v.rl};}
}A[N],B[N],C[N],D[N],AC[N],BD[N],ABC[N];
void FFT(cop *a,int op) {
for(int i=0;i<up;i++)if(rev[i]>i)swap(a[i],a[rev[i]]);
for(int mid=1;mid<up;mid<<=1) {
cop w1=(cop){op*sin(pi/mid),cos(pi/mid)};
for(int len=mid<<1,l=0;l<up;l+=len) {
cop W=(cop){0,1};
for(int i=0;i<mid;i++,W=W*w1) {
int p=l+i,q=p+mid;
cop x=a[p],y=W*a[q];
a[p]=x+y;a[q]=x-y;
}
}
}
}
void gt_up(int len) {
up=1,l=0;
while(up<len) {up<<=1,l++;}
for(int i=1;i<up;i++) {rev[i]=(rev[i>>1]>>1)|((i&1)<<(l-1));}
}
ll ans[N];
void Mul(ll *f,ll *g) {
for(int i=0;i<up;i++) {
A[i]=(cop){0,f[i]/bas};B[i]=(cop){0,f[i]%bas};
C[i]=(cop){0,g[i]/bas};D[i]=(cop){0,g[i]%bas};
}
FFT(A,-1),FFT(B,-1),FFT(C,-1),FFT(D,-1);
for(int i=0;i<up;i++) {
AC[i]=A[i]*C[i],ABC[i]=A[i]*D[i]+B[i]*C[i],BD[i]=B[i]*D[i];
}
FFT(AC,1),FFT(ABC,1),FFT(BD,1);
for(int i=0;i<up;i++) {
ll ac=(ll)round(AC[i].rl/up)%mod,abc=(ll)round(ABC[i].rl/up)%mod,bd=(ll)round(BD[i].rl/up)%mod;
f[i]=(ac*bas%mod*bas+abc*bas+bd)%mod;
}
}
void pw_Mul(ll *f) {
for(int i=0;i<up;i++) {
A[i]=(cop){0,f[i]/bas};B[i]=(cop){0,f[i]%bas};
}
FFT(A,-1),FFT(B,-1);
for(int i=0;i<up;i++) {
AC[i]=A[i]*A[i];ABC[i]=A[i]*B[i];BD[i]=B[i]*B[i];
}
FFT(AC,1),FFT(ABC,1),FFT(BD,1);
for(int i=0;i<up;i++) {
ll ac=(ll)round(AC[i].rl/up)%mod,abc=(ll)round(ABC[i].rl/up)%mod,bd=(ll)round(BD[i].rl/up)%mod;
f[i]=(ac*bas%mod*bas+2*abc*bas%mod+bd)%mod;
// printf("%lld ",(f[i]%mod+mod)%mod);
}
// puts("");
}
void solve(int dep,ll *b) { //b为该层(%x^{dep})得到的结果
if(dep==1) {b[0]=ksm(f[0],mod-2);return;}
solve((dep+1)>>1,b);
gt_up(dep<<1);
for(int i=0;i<up;i++)c[i]=b[i],a[i]=(i<dep)?f[i]:0;
pw_Mul(c);
for(int i=dep;i<up;i++)c[i]=0;
Mul(a,c);
for(int i=0;i<dep;i++) {
b[i]=(2*b[i]-a[i])%mod;
if(b[i]<mod)b[i]+=mod;
}
// printf("S:\n");
// for(int i=0;i<up;i++)printf("%lld ",(b[i]+mod)%mod);puts("");
}
int main() {
// freopen("P4239_16.in","r",stdin);
// freopen("ans.out","w",stdout);
scanf("%d",&n);
for(int i=0;i<n;i++) {scanf("%lld",&f[i]);}
solve(n,ans);
for(int i=0;i<n;i++) {printf("%lld ",(ans[i]+mod)%mod);}
return 0;
}
注意
%.0lf以及浮点型转整形,是保留整数;除法不是下取整是向〇取整;四舍五入直接用round,负数就不能+0.5要-0.5转整型。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· winform 绘制太阳,地球,月球 运作规律
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人