题意:
给多项式\(F(x)\)和\(G(x)\),求\(n\)次多项式\(H(x)\),满足\(H(x)=F(G(x)) (mod\ x^{n+1})\)。
luogu传送门
思路:
题意具体可以把多项式\(G\)当作自变量,每次次幂后,乘\(F\)的系数。
想要暴力解决问题,试试分块。
令\(L= \left\lceil\sqrt{n}\ \right\rceil\)
\(H(x)=\sum\limits_{i=0}^n([x^i]F(x))*[G(x)]^i (mod\ x^{n+1})\)
\(\ \ \ \ \ \ \ \ \ = \sum\limits_{i=0}^{L-1} [G(x)]^{iL} \sum\limits_{j=0}^{L-1}([x^{iL+j}]F(x))[G(x)]^j\)
可以\(O(\sqrt{n}*nlogn)\)预处理出\(G(x)^i\)以及\(G(x)^{iL}\)
然后\(O(n^2)\)枚举,累加第二个\(\sum\)。
然后第二个\(\sum\)得到的结果和前面多项式乘,用\(O(\sqrt{n}*nlogn)\)
大概总时间复杂度?
\(O(\sqrt{n}nlogn+n^2)\)
而且这个\(n^2\)常数挺低的,时限也很大。
*注意:我因为预处理问题调了很久,预处理时,可能会爆,讨论版有人说\(lim\)最大设为\(n^3-2\)就不会爆,事实上我的就会,我布吉岛别人怎么写的。
我最后还是改回,每算到一次\(G^i\)的值,截断一次(从\(n\)位开始往后赋值为\(0\))。
code:
戳我
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const int M=100005;
const int L=155;
const int mod=998244353;
int n,m,Blen;
ll A[N],gen[2][N],inv3=332748118,B[L][M],B_[L][M],tb[L][M],tb_[L][M],ans[N],f[N],i_up;
int up,l,rev[N];
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;}
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));}
}
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];
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 init() {
scanf("%d%d",&n,&m);n++;m++;
Blen=ceil(sqrt(n));
for(int i=0;i<n;i++)scanf("%lld",&A[i]);
for(int i=0;i<m;i++)scanf("%lld",&B[1][i]),tb[1][i]=B[1][i];
gt_up(n<<1);
i_up=ksm(up,mod-2);
// printf("up=%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) {
gen[0][i>>1]=gen[0][i]*gen[0][i]%mod;
gen[1][i>>1]=gen[1][i]*gen[1][i]%mod;
}
tb[0][0]=B[0][0]=B_[0][0]=tb_[0][0]=1;
NTT(tb[0],0),NTT(tb_[0],0);
NTT(tb[1],0);
for(int i=2;i<=Blen;i++) {
for(int j=0;j<up;j++) B[i][j]=tb[i-1][j]*tb[1][j]%mod;
NTT(B[i],1);
for(int j=0;j<n;j++) tb[i][j]=B[i][j]=B[i][j]*i_up%mod;
for(int j=n;j<up;j++)tb[i][j]=B[i][j]=0;
NTT(tb[i],0);
}
// printf("!%lld!\n",B[1][0]);
// for(int j=0;j<up;j++) tb_[1][j]=tb[Blen][j],B_[1][j]=B[Blen][j];
for(int j=0;j<n;j++) tb_[1][j]=B_[1][j]=B[Blen][j];
// for(int j=0;j<up;j++)printf("!%lld %lld\n",tb_[1][j],B_[Blen][j]);
NTT(tb_[1],0);
for(int i=2;i<Blen;i++) {
for(int j=0;j<up;j++) B_[i][j]=tb_[i-1][j]*tb_[1][j]%mod;
NTT(B_[i],1);
for(int j=0;j<n;j++) tb_[i][j]=B_[i][j]=B_[i][j]*i_up%mod;
for(int j=n;j<up;j++) tb_[i][j]=B_[i][j]=0; //截取
NTT(tb_[i],0);
// printf("i=%d:~~\n",i);
// for(int j=0;j<n;j++) {printf("%lld ",(B_[i][j]+mod)%mod);}
// puts("");
}
}
void solve() {
for(int i=0;i<Blen;i++) {
// printf("i=%d~~~~\n",i);
for(int j=0;j<Blen;j++) {
ll w=A[i*Blen+j];
for(int k=0;k<n;k++) {
f[k]=(f[k]+B[j][k]*w)%mod;
// printf("(B[%d][%d]=%lld) %lld\n",j,k,(B[j][k]+mod)%mod,(f[k]%mod+mod)%mod);
}
}
// for(int k=0;k<up;k++)printf("f[%d] = %lld\n",k,(f[k]%mod+mod)%mod);
NTT(f,0);
for(int k=0;k<up;k++) f[k]=f[k]*tb_[i][k]%mod;
NTT(f,1);
for(int k=0;k<n;k++) {
ans[k]=(ans[k]+f[k]*i_up)%mod;
f[k]=0;
}
for(int k=n;k<up;k++)f[k]=0;
}
for(int i=0;i<n;i++)printf("%lld ",(ans[i]%mod+mod)%mod);
}
int main() {
// freopen("data.in","r",stdin);
// freopen("A.out","w",stdout);
init();
solve();
return 0;
}
ps.说实话,这个东西没什么卵用