loj #150. 挑战多项式——模板总结

题目

这个题堪称 简易模板全家桶

关于各个函数的实现,大多数都是利用牛顿迭代公式+倍增。

下面的 f , b , ( b ) f,b,(b^*) 分别为已知多项式,当前所求多项式和上一个状态(规模小一半)的多项式

s q r t sqrt

b ( x ) 2 = f ( x )    > b ( x ) 2 f ( x ) = 0 b(x)^2=f(x) ~~->b(x)^2-f(x)=0
φ ( b ( x ) ) = b ( x ) 2 f ( x ) 设\varphi(b(x))=b(x)^2-f(x)
φ ( b ( x ) ) = 2 b ( x ) 则\varphi'(b(x))=2*b(x)
, 此时,我们求函数零点
b ( x ) = ( b ) ( x ) φ ( ( b ) ( x ) ) φ ( ( b ) ( x ) ) = ( b ) ( x ) ( b ) 2 ( x ) f ( x ) 2 ( b ) ( x ) = ( b ) 2 ( x ) + f ( x ) 2 ( b ) ( x ) b(x)=(b^*)(x)-\dfrac{\varphi((b^*)(x))}{\varphi'((b^*)(x))}=(b^*)(x)-\dfrac{(b^*)^2(x)-f(x)}{2(b^*)(x)}=\dfrac{(b^*)^2(x)+f(x)}{2(b^*)(x)}

以下证明略.

i n v : b ( x ) = 2 ( b ) ( x ) f ( x ) ( b ) 2 ( x ) inv:b(x)=2*(b^*)(x)-f(x)*(b^*)^2(x)

l n : b ( x ) b ( x ) = f ( x ) ln:\dfrac{b'(x)}{b(x)}=f'(x)

e x p : b ( x ) = ( b ) ( x ) ( 1 l n ( ( b ) ( x ) ) + f ( x ) ) exp: b(x)=(b^*)(x)(1-ln ((b^*)(x))+f(x))

f ( x ) k = e l n ( f ( x ) ) k f(x)^k=e^{ln(f(x))*k}

代码:

#include<ctime>
#include<cstdio>
#include<cctype>
#include<iostream>
#include<algorithm>
#define gc (p1==p2&&(p2=(p1=buf)+fread(buf,1,N,stdin),p1==p2)?EOF:*p1++)
using namespace std;
typedef long long ll;
const int N=1<<18|10,g=3,G=332748118,mod=998244353;

char buf[N],*p1=buf,*p2=buf;
void qr(int &x) {
	char c=gc; x=0;
	while(!isdigit(c))c=gc;
	while(isdigit(c))x=x*10+c-'0',c=gc;
}
void qw(int x) {
	if(x/10) qw(x/10);
	putchar(x%10+'0');
}

int n,m,k,tr[N],f[N];

ll power(ll a,ll b=mod-2) {
	ll c=1;
	while(b) {
		if(b&1) c=c*a%mod;
		a=a*a%mod; b=b>>1;
	}
	return c;
}

namespace Cipolla {
	ll w,n,p=mod;
	struct CP {
		ll x,y;
		CP(ll x=1,ll y=0):x(x),y(y){}
		CP operator *(CP b) const {
			return CP( (x*b.x+y*b.y%p*w)%p , (x*b.y+y*b.x)%p );
		}
	};
	CP Pow(CP a,ll b=p+1>>1) {
		CP c;
		for(  ;b;b=b>>1,a=a*a)
			if(b&1) c=c*a;
		return c;
	}
	bool pd(ll x) {return power(x,p-1>>1)==p-1;}
	int solve(ll t) {
		n=t;
		if(!n) return 0;
		ll a;
		do {
			a=1LL*rand()*rand()%p;
			w=( (a*a-n)%p+p )%p;
		} while(!pd(w));
		ll x=Pow(CP(a,1)).x,y=p-x;
		if(x>y) return y;
		return x;
	}
}

int calc(int x) {//丢入长度
	if(x==(x&-x)) return x;
	int n=1;while(n<x)n<<=1;
	return n;
}
	
void upd(int &a) {a+=a>>31&mod;}

int pre[2][22];
void NTT(int *f,int v,int n) {
	for(int i=1;i<n;i++)
		if(i<tr[i]) swap(f[i],f[tr[i]]);
	for(int p=2,j=1;p<=n;p<<=1,j++) {
		int len=p>>1;
		ll tg=pre[v][j],buf,t;
		for(int i=0;i<n;i+=p) {
			buf=1;
			for(int l=i;l<i+len;l++) {
				t=f[l+len]*buf%mod;
				upd(f[l+len]=f[l]-t);
				upd(f[l] += t-mod);
				buf=buf*tg%mod;
			}
		}
	}
}

int a[N],b[N],w[N];
void mult(int *a,int *b,int n,int m) {
	int *c=w;
	n<<=1; for(int i=1;i<n;i++)tr[i]=(tr[i>>1]>>1)|(i&1?n>>1:0);
	if(a!=b) {
		for(int i=0;i*2<n;i++) c[i]=b[i];
		for(int i=n>>1;i<n;i++) c[i]=0;
		NTT(c,1,n);
	}
	else c=a;
	NTT(a,1,n);  for(int i=0;i<n;i++) a[i]=(ll)a[i]*c[i]%mod;
	NTT(a,0,n); ll inv=power(n);
	for(int i=0;i<m;i++) a[i]=a[i]*inv%mod;
	for(int i=m;i<n;i++) a[i]=0;
}

void inv(int *f,int n) {
	n=calc(n);
	b[0]=power(f[0]);
	for(int len=1,p=2;p<=n;len=p,p <<= 1) {
		for(int i=0;i<len;i++)
			upd(a[i]=2*b[i]-mod);
		mult(b,b,len,p);mult(b,f,p,p);
		for(int i=0;i<p;i++)
			upd(b[i]=a[i]-b[i]);
	}
	for(int i=0;i<n;i++) f[i]=b[i],a[i]=b[i]=0;
}

int h[N],s[N];
void Sqrt(int *f,int n) {
	n=calc(n);
	s[0]=Cipolla::solve(f[0]);
	for(int len=1,p=2;p<=n;len=p,p <<= 1) {
		for(int i=0;i<p;i++) upd(h[i]=2*s[i]-mod);
		inv(h,p); mult(s,s,len,p);
		for(int i=0;i<p;i++) upd(s[i]+=f[i]-mod);
		mult(s,h,p,p);
	}
	for(int i=0;i<n;i++) f[i]=s[i],h[i]=s[i]=0;
}

void Dao(int *a,int *b,int n) {
	for(int i=1;i<n;i++) b[i-1]=(ll)a[i]*i%mod;
	b[n-1]=0;
}
int Inv[N];//
void Ji(int *a,int *b,int n) {
	for(int i=n-1; i;i--) b[i]=(ll)a[i-1]*Inv[i]%mod;
	b[0]=0;
}

int c[N];
void Ln(int *f,int n) {
	n=calc(n);Dao(f,c,n);
	inv(f,n); mult(f,c,n,n);
	Ji(f,f,n);
}

int e[N],E[N];
void Exp(int *f,int n) {
	n=calc(n);
	e[0]=1;
	for(int p=2;p<=n;p<<=1) {
		for(int i=0;i<p;i++) E[i]=e[i];
		Ln(E,p); upd(--E[0]);
		for(int i=0;i<p;i++) upd(E[i]=-E[i]+f[i]);
		mult(e,E,p,p);
	}
	for(int i=0;i<n;i++) f[i]=e[i],e[i]=E[i]=0;
}

int tmp[N];

int main() {
	srand(time(0));
	qr(m); qr(k); m++; n=calc(m);
	Inv[1]=1; for(int i=2;i<n;i++) Inv[i]=(ll)Inv[mod%i]*(mod-mod/i)%mod;
	for(int i=1;i<20;i++) 
		pre[0][i]=power(G,mod>>i),
		pre[1][i]=power(g,mod>>i);
	
	for(int i=0;i<m;i++) qr(f[i]),tmp[i]=f[i];
	
	Sqrt(tmp,n);inv(tmp,n);Ji(tmp,tmp,n);Exp(tmp,n); 
	for(int i=0;i<n;i++) upd(tmp[i]=f[i]-tmp[i]);
	upd(tmp[0]=(tmp[0]+2-f[0])%mod);
	Ln(tmp,n); tmp[0]=(tmp[0]+1)%mod;
	Ln(tmp,n); for(int i=0;i<n;i++) tmp[i]=(ll)tmp[i]*k%mod;
	Exp(tmp,n);Dao(tmp,tmp,n);
	for(int i=0;i<m-1;i++)qw(tmp[i]),putchar(' ');
	
	return 0;
}
发布了71 篇原创文章 · 获赞 88 · 访问量 5457

猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/104791038