# LG5050 多项式多点求值

$n,m∈[1,64000]$

## 题解

typedef vector<int> polynomial;
void num_trans(polynomial&a,int dir){
int lim=a.size();
static vector<int> rev,w[2];
if(rev.size()!=lim){
rev.resize(lim);
int len=log2(lim);
for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
for(int dir=0;dir<2;++dir){
w[dir].resize(lim);
w[dir][0]=1,w[dir][1]=fpow(g[dir],(mod-1)/lim);
for(int i=2;i<lim;++i) w[dir][i]=mul(w[dir][i-1],w[dir][1]);
}
}
for(int i=0;i<lim;++i)if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int step=1;step<lim;step<<=1){
int quot=lim/(step<<1);
for(int i=0;i<lim;i+=step<<1){
int j=i+step;
for(int k=0;k<step;++k){
int t=mul(w[dir][quot*k],a[j+k]);
}
}
}
if(dir){
int ilim=fpow(lim,mod-2);
for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
}
}
polynomial poly_inv(polynomial a,int n){
polynomial b(1,fpow(a[0],mod-2));
if(n==1) return b;
int lim=2;
for(;lim<n;lim<<=1){
polynomial a1(a.begin(),a.begin()+lim);
a1.resize(lim<<1),num_trans(a1,0);
b.resize(lim<<1),num_trans(b,0);
num_trans(b,1),b.resize(lim);
}
a.resize(lim<<1),num_trans(a,0);
b.resize(lim<<1),num_trans(b,0);
num_trans(b,1),b.resize(n);
return b;
}
polynomial poly_div(polynomial f,polynomial g){
int n=f.size()-1,m=g.size()-1;
reverse(g.begin(),g.end()),g.resize(n-m+1),g=poly_inv(g,n-m+1);
reverse(f.begin(),f.end()),f.resize(n-m+1);
int lim=1<<int(ceil(log2(((n-m)<<1)+1)));
f.resize(lim),num_trans(f,0);
g.resize(lim),num_trans(g,0);
for(int i=0;i<lim;++i) f[i]=mul(f[i],g[i]);
num_trans(f,1),f.resize(n-m+1);
return reverse(f.begin(),f.end()),f;
}
polynomial poly_mod(polynomial f,polynomial g){
int n=f.size()-1,m=g.size()-1;
polynomial q=poly_div(f,g);
int lim=1<<int(ceil(log2(n+1)));
q.resize(lim),num_trans(q,0);
g.resize(lim),num_trans(g,0);
for(int i=0;i<lim;++i) q[i]=mul(q[i],g[i]);
num_trans(q,1);
return f.resize(m),f;
}

co int N=64000+1;
int a[N];
polynomial s[N<<2];

#define lc (x<<1)
#define rc (x<<1|1)
polynomial poly_mul(polynomial a,polynomial b){
int n=a.size()-1,m=b.size()-1;
int lim=1<<int(ceil(log2(n+m+1)));
a.resize(lim),num_trans(a,0);
b.resize(lim),num_trans(b,0);
for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
num_trans(a,1),a.resize(n+m+1);
return a;
}
void build(int x,int l,int r){
if(l==r){
s[x].resize(2);
s[x][0]=mod-a[l],s[x][1]=1;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
s[x]=poly_mul(s[lc],s[rc]);
}
void solve(int x,int l,int r,polynomial f){
if(l==r){
printf("%d\n",f[0]);
return;
}
int mid=(l+r)>>1;
solve(lc,l,mid,poly_mod(f,s[lc])),solve(rc,mid+1,r,poly_mod(f,s[rc]));
}
int main(){
if(!m) return 0;
polynomial f(n+1);
build(1,1,m);
if(n>=m) f=poly_mod(f,s[1]);
solve(1,1,m,f);
return 0;
}

## 卡常数做法

$[l,r]$递归的时候，$[l,\text{mid}]$传入$F_{l,\text{mid}}(x)=\text{mul}(F_{l,r}(x),\prod_{i=\text{mid}+1}^r(1-a_ix))$$[\text{mid}+1,r]$传入$F_{\text{mid+1,r}(x)}=\text{mul}(F_{l,r}(x),\prod_{i=l}^{\text{mid}}(1-a_ix))$

CO int N=1<<17;
int omg[2][N],rev[N];

void NTT(poly&a,int dir){
int lim=a.size(),len=log2(lim);
for(int i=0;i<lim;++i){
int r=rev[i]>>(17-len);
if(i<r) swap(a[i],a[r]);
}
for(int i=1;i<lim;i<<=1)
for(int j=0;j<lim;j+=i<<1)for(int k=0;k<i;++k){
int t=mul(omg[dir][N/(i<<1)*k],a[j+i+k]);
}
if(dir){
int ilim=fpow(lim,mod-2);
for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
}
}
poly operator~(poly a){
int n=a.size();
poly b={fpow(a[0],mod-2)};
if(n==1) return b;
a.resize(1<<(int)ceil(log2(n)));
for(int lim=2;lim<2*n;lim<<=1){
poly c(a.begin(),a.begin()+lim);
c.resize(lim<<1),NTT(c,0);
b.resize(lim<<1),NTT(b,0);
for(int i=0;i<lim<<1;++i) b[i]=mul(2+mod-mul(c[i],b[i]),b[i]);
NTT(b,1),b.resize(lim);
}
return b.resize(n),b;
}
poly operator*(poly a,poly b){
if(a.size()<=20 or b.size()<=20){
int n=a.size()-1,m=b.size()-1;
a.resize(n+m+1);
for(int i=n;i>=0;--i){
a[i]=mul(a[i],b[0]);
}
return a;
}
int n=a.size()+b.size()-1,lim=1<<(int)ceil(log2(n));
a.resize(lim),NTT(a,0);
b.resize(lim),NTT(b,0);
for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
NTT(a,1),a.resize(n);
return a;
}
poly operator/(poly a,poly b){
if(a.size()<=20 or b.size()<=20){
int n=a.size()-1,m=b.size()-1;
for(int i=0;i<=n;++i){
a[i]=mul(a[i],b[0]);
}
return a;
}
int n=a.size()-1,m=b.size()-1;
if(n<m) b.resize(n+1),m=n;
reverse(b.begin(),b.end());
int lim=1<<(int)ceil(log2(n+m+1));
a.resize(lim),NTT(a,0);
b.resize(lim),NTT(b,0);
for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
NTT(a,1);
for(int i=0;i<=n;++i) a[i]=a[i+m];
return a.resize(n+1),a;
}

int a[N];
poly g[N];

#define lc (x<<1)
#define rc (x<<1|1)
#define mid ((l+r)>>1)
void build(int x,int l,int r){
build(lc,l,mid),build(rc,mid+1,r);
g[x]=g[lc]*g[rc];
}
void solve(int x,int l,int r,CO poly&f){
if(l==r) {printf("%d\n",f[0]); return;}
poly lf=f/g[rc];lf.resize(mid-l+2);
solve(lc,l,mid,lf);
poly rf=f/g[lc];rf.resize(r-mid+1);
solve(rc,mid+1,r,rf);
}
#undef lc
#undef rc
#undef mid

int main(){
omg[0][0]=1,omg[0][1]=fpow(3,(mod-1)/N);
omg[1][0]=1,omg[1][1]=fpow(omg[0][1],mod-2);
rev[0]=0,rev[1]=1<<16;
for(int i=2;i<N;++i){
omg[0][i]=mul(omg[0][i-1],omg[0][1]);
omg[1][i]=mul(omg[1][i-1],omg[1][1]);
rev[i]=rev[i>>1]>>1|(i&1)<<16;
}
poly f(n+1);
build(1,1,m);
g[1].resize(n+1),f=f/~g[1],f.resize(m+1);
solve(1,1,m,f);
return 0;
}

# LG5158 多项式快速插值

$1⩽n⩽100000$

## 题解

$f(x)=\sum_{i = 1}^{n} y_i \prod_{i \not = j} \frac{x - x_j}{x_i - x_j}$

$f(x)=\sum_{i = 1}^{n}{ y_i\over \prod_{i \not = j}{x_i - x_j}} \prod_{i \not = j}(x - x_j)$

$\lim_{x\to a}f(x)=0,\lim_{x\to a}g(x)=0$

$\lim_{x\to a}{f(x)\over g(x)}=\lim_{x\to a}{f'(x)\over g'(x)}$

\begin{aligned} f_{l,r}&=\sum_{i = l}^{r}{ y_i\over g'(x_i)} \prod_{j=l,i \not = j}^r(x - x_j)\\&=\prod_{j=mid+1}^r(x - x_j)\sum_{i = l}^{mid}{ y_i\over g'(x_i)} \prod_{j=l,i \not = j}^{mid}(x - x_j)+\prod_{j=l}^{mid}(x - x_j)\sum_{i = mid+1}^{r}{ y_i\over g'(x_i)} \prod_{j=mid+1,i \not = j}^{r}(x - x_j)\\&=\prod_{j=mid+1}^r(x - x_j)f_{l,mid}+\prod_{j=l}^{mid}(x - x_j)f_{mid+1,r}\\ \end{aligned}

typedef vector<int> polynomial;
void num_trans(polynomial&a,int dir){
int lim=a.size();
static vector<int> rev,w[2];
if(rev.size()!=lim){
rev.resize(lim);
int len=log2(lim);
for(int i=0;i<lim;++i) rev[i]=rev[i>>1]>>1|(i&1)<<(len-1);
for(int dir=0;dir<2;++dir){
static co int g[2]={3,332748118};
w[dir].resize(lim);
w[dir][0]=1,w[dir][1]=fpow(g[dir],(mod-1)/lim);
for(int i=2;i<lim;++i) w[dir][i]=mul(w[dir][i-1],w[dir][1]);
}
}
for(int i=0;i<lim;++i)if(i<rev[i]) swap(a[i],a[rev[i]]);
for(int step=1;step<lim;step<<=1){
int quot=lim/(step<<1);
for(int i=0;i<lim;i+=step<<1){
int j=i+step;
for(int k=0;k<step;++k){
int t=mul(w[dir][quot*k],a[j+k]);
}
}
}
if(dir){
int ilim=fpow(lim,mod-2);
for(int i=0;i<lim;++i) a[i]=mul(a[i],ilim);
}
}
polynomial poly_inv(polynomial a,int n){
polynomial b(1,fpow(a[0],mod-2));
if(n==1) return b;
int lim=2;
for(;lim<n;lim<<=1){
polynomial a1(a.begin(),a.begin()+lim);
a1.resize(lim<<1),num_trans(a1,0);
b.resize(lim<<1),num_trans(b,0);
num_trans(b,1),b.resize(lim);
}
a.resize(lim<<1),num_trans(a,0);
b.resize(lim<<1),num_trans(b,0);
num_trans(b,1),b.resize(n);
return b;
}
polynomial poly_div(polynomial f,polynomial g){
int n=f.size()-1,m=g.size()-1;
reverse(g.begin(),g.end()),g.resize(n-m+1),g=poly_inv(g,n-m+1);
reverse(f.begin(),f.end()),f.resize(n-m+1);
int lim=1<<int(ceil(log2(((n-m)<<1)+1)));
f.resize(lim),num_trans(f,0);
g.resize(lim),num_trans(g,0);
for(int i=0;i<lim;++i) f[i]=mul(f[i],g[i]);
num_trans(f,1),f.resize(n-m+1);
return reverse(f.begin(),f.end()),f;
}
polynomial poly_mod(polynomial f,polynomial g){
int n=f.size()-1,m=g.size()-1;
polynomial q=poly_div(f,g);
int lim=1<<int(ceil(log2(n+1)));
q.resize(lim),num_trans(q,0);
g.resize(lim),num_trans(g,0);
for(int i=0;i<lim;++i) q[i]=mul(q[i],g[i]);
num_trans(q,1);
return f.resize(m),f;
}

polynomial poly_mul(polynomial a,polynomial b){
int n=a.size()-1,m=b.size()-1;
if((LL)n*m<=5000){ // edit 1
polynomial c(n+m+1);
for(int i=0;i<=n;++i)
return c;
}
int lim=1<<int(ceil(log2(n+m+1)));
a.resize(lim),num_trans(a,0);
b.resize(lim),num_trans(b,0);
for(int i=0;i<lim;++i) a[i]=mul(a[i],b[i]);
num_trans(a,1),a.resize(n+m+1);
return a;
}
if(a.size()<b.size()) swap(a,b);
return a;
}

co int N=100000+1;
#define lc (x<<1)
#define rc (x<<1|1)
namespace eval{
int n,m,a[N],ans[N];
polynomial f,s[N<<2];

void build(int x,int l,int r){
if(l==r){
s[x].resize(2);
s[x][0]=mod-a[l],s[x][1]=1;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
s[x]=poly_mul(s[lc],s[rc]);
}
void solve(int x,int l,int r,polynomial f){
if(l==r){
ans[l]=f[0];
return;
}
int mid=(l+r)>>1;
solve(lc,l,mid,poly_mod(f,s[lc])),solve(rc,mid+1,r,poly_mod(f,s[rc]));
}
void main(){
build(1,1,m);
if(n>=m) f=poly_mod(f,s[1]);
solve(1,1,m,f);
}
}

int X[N],Y[N];
polynomial g[N<<2],f[N<<2];
void build(int x,int l,int r){
if(l==r){
g[x].resize(2);
g[x][0]=mod-X[l],g[x][1]=1;
return;
}
int mid=(l+r)>>1;
build(lc,l,mid),build(rc,mid+1,r);
g[x]=poly_mul(g[lc],g[rc]);
}
void solve(int x,int l,int r){
if(l==r){
f[x].assign(1,mul(Y[l],fpow(eval::ans[l],mod-2)));
return;
}
int mid=(l+r)>>1;
solve(lc,l,mid),solve(rc,mid+1,r);
}
int main(){
//	freopen("LG5158.in","r",stdin),freopen("LG5158.out","w",stdout);
build(1,1,n);
eval::n=n-1,eval::f.resize(n);
for(int i=0;i<=eval::n;++i) eval::f[i]=mul(g[1][i+1],i+1);
eval::m=n;
for(int i=1;i<=eval::m;++i) eval::a[i]=X[i];
eval::main();
solve(1,1,n);
for(int i=0;i<n;++i) printf("%d ",f[1][i]);
return 0;
}

posted on 2020-07-23 20:10  autoint  阅读(110)  评论(0编辑  收藏