Polynomial Multiplication: Practice Summary

Posted by erfg1 on Wed, 06 Oct 2021 22:26:17 +0200

Preface

These two days, because the National Day training is all the generation function of the yin, so I learned a little bit about it.
Actually I learned FFT and NTT
It's a little bit of a skill.
Enter the polynomial to discover the vastness of the inner world
However, since none of these items are NOIP test points and don't seem to be very helpful for advanced problem solving (unlike some fairy data structures), let's put them first.
But these days the polynomials are all blue and purple.

Power

Introduction questions
Bare and simple
But I really didn't know what polynomials were.
So I still looked at the solution
... without losing people! (straightforward and energetic)
One trick is to flip the function
But this by itself is hardly a skill.
qwq

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
const int N=1e6+100;
const int M=150;
const int mod=998244353;
const double pi=acos(-1.0);
inline ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int n,m,lim,k;
struct node{
	double x,y;
	node(double a=0,double b=0){
		x=a;y=b;
	}
}A[N],B[N],C[N];
il node operator * (node a,node b){
	return (node){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
}
il node operator + (node a,node b){
	return (node){a.x+b.x,a.y+b.y};
}
il node operator - (node a,node b){
	return (node){a.x-b.x,a.y-b.y};
}
int r[N];
il void fft(node *x,int lim,int flag){
	for(int i=0;i<=lim;i++){
		if(i<r[i]) swap(x[i],x[r[i]]);
	}
	for(int l=1;l<lim;l<<=1){
		node o(cos(pi/l),flag*sin(pi/l));
		for(int st=0;st<=lim;st+=l<<1){
			node t(1,0);
			for(int j=0;j<l;j++,t=t*o){
				node u=x[st+j],v=t*x[st+j+l];
				x[st+j]=u+v;
				x[st+j+l]=u-v;
			}
		}
	}
	return;
}
int main(){
	n=read();
	for(int i=1;i<=n;i++){
		scanf("%lf",&A[i].x);
		B[i].x=(double)(1.0/i/i);
		C[n-i].x=A[i].x;
	}
	int L=0,lim=1;
	while(lim<=n<<1){lim<<=1;L++;}
	for(int i=1;i<=lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
	fft(A,lim,1);fft(B,lim,1);fft(C,lim,1);
	for(int i=0;i<=lim;i++){
		A[i]=A[i]*B[i];C[i]=C[i]*B[i];
	}
	fft(A,lim,-1);fft(C,lim,-1);
	for(int i=1;i<=n;i++) printf("%lf\n",(A[i].x-C[n-i].x)/lim);
	return 0;
}
/*

*/

gift

I did it myself
Clearly we have to split the squares
Then find that the added brightness is O1 calculable
Then it turns into minimizing a strange thing
Just double the length of the cycle

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define il inline
const int N=2e6+100;
const double pi=acos(-1.0);
ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int n,m;
struct node{
	double x,y;
	node (double a=0,double b=0){
		x=a;y=b;
	}
}A[N],B[N];
il node operator *(node a,node b){
	return (node){a.x*b.x-a.y*b.y,a.x*b.y+a.y*b.x};
}
il node operator +(node a,node b){
	return (node){a.x+b.x,a.y+b.y};
}
il node operator -(node a,node b){
	return (node){a.x-b.x,a.y-b.y};
}
int r[N];
il void fft(node *x,int lim,int flag){
	for(int i=1;i<lim;i++){
		if(i<r[i]) swap(x[i],x[r[i]]);
	}
	for(int l=1;l<lim;l<<=1){
		node o(cos(pi/l),flag*sin(pi/l));
		for(int st=0;st<lim;st+=l<<1){
			node t(1,0);
			for(int i=0;i<l;i++,t=t*o){
				node u=x[st+i],v=t*x[st+l+i];
				x[st+i]=u+v;x[st+l+i]=u-v;
			}
		}
	}
}
ll x[N],y[N],tot,Sx,Sy,ans=2e18;
int main(){
	n=read();m=read();
	for(int i=1;i<=n;i++) x[i]=read();
	for(int i=1;i<=n;i++) y[i]=read();
	for(int i=1;i<=n;i++){
		tot+=x[i]*x[i]+y[i]*y[i];
		Sx+=x[i];Sy+=y[i];
	}
	if(Sy<Sx) swap(Sy,Sx);
	ll a=(Sy-Sx)/n,b=a+1;
	if(a*a*n+2*a*(Sx-Sy)>b*b*n+2*b*(Sx-Sy)) swap(a,b);
	tot+=a*a*n+2*a*(Sx-Sy);
	//printf("a=%d\n",a);
	for(int i=1;i<=n;i++){
		A[i].x=x[i];
		B[n+n-i].x=B[n-i].x=y[i];
	}
	int lim=1,L=0;
	while(lim<3*n+2){lim<<=1;L++;}
	for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
	fft(A,lim,1);fft(B,lim,1);
	for(int i=0;i<lim;i++) A[i]=A[i]*B[i];
	fft(A,lim,-1);
	for(int i=0;i<n;i++){
		ll now=(ll)(A[n-i+n].x/lim+0.5);
		ans=min(ans,tot-2*now);
	}
	printf("%lld\n",ans);
}

Differential and Prefix Sum

It looks completely naked and I just can't
A key idea in this topic is that convolution satisfies the law of Union
So all you have to do is find the k-th power of the brainless persimmon with k=1
The prefix is identical to the style of the mock exam
Mainly stuck in the difference
Just one volume 1 − x 1-x 1−x
In fact, it is not necessary to "discover", but it is easy to find out the generating functions.
Then the k-th binomial is like drinking water

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+100;
const int mod= 1004535809; 
#define il inline
inline ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();x%=mod;}
	return x*f;
}
ll n,k;
ll A[N],B[N],r[N],lim,L;
ll ksm(ll x,ll k){
	ll res=1;
	while(k){
		if(k&1) res=res*x%mod;
		x=x*x%mod;
		k>>=1;
	}
	return res;
}
void ntt(ll *x,int flag){
	for(int i=0;i<lim;i++){
		if(i<r[i]) swap(x[i],x[r[i]]);
	}
	for(int l=1;l<lim;l<<=1){
		ll t0=ksm(3,(mod-1)/(l<<1));if(flag==-1) t0=ksm(t0,mod-2);
		for(int st=0;st<lim;st+=l<<1){
			ll t=1;
			for(int i=0;i<l;i++,t=t*t0%mod){
				ll u=x[st+i],v=t*x[st+i+l]%mod;
				x[st+i]=(u+v)%mod;
				x[st+i+l]=(u-v+mod)%mod;
			}
		}
	}
	if(flag==-1){
		ll ni=ksm(lim,mod-2);
		for(int i=0;i<lim;i++) x[i]=x[i]*ni%mod;
	}
}
int main(){
	n=read();k=read();int op=read();
	for(int i=1;i<=n;i++) A[i]=read();
	if(op==0){
		B[0]=1;
		for(int i=1;i<=n;i++){
			B[i]=B[i-1]*(k+i-1)%mod*ksm(i,mod-2)%mod;
			//printf("i=%d %lld\n",i,B[i]);
		}
	}
	else{
		//B[0]=k%2?-1:1;
		B[0]=1;
		for(int i=1;i<=n;i++){
			B[i]=-1*B[i-1]*(k-i+1)%mod*ksm(i,mod-2)%mod;
			//B[i]=(B[i]+mod)%mod;
			//printf("i=%d %lld\n",i,B[i]);
		}
		for(int i=0;i<=n;i++) B[i]=(B[i]+mod)%mod;
	}
	lim=1;
	while(lim<n+n+1) lim<<=1,L++;
	for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
	ntt(A,1);ntt(B,1);
	for(int i=0;i<lim;i++) A[i]=A[i]*B[i]%mod;
	ntt(A,-1);
	for(int i=1;i<=n;i++) printf("%lld ",A[i]);
	return 0;
}
/*
3 1 1
1 1 1
*/

The knowledge of pioneers

The picture of the face is cute!
It's not too difficult, but for me just getting started, it can also be a temporary graduation topic
What I do:

  1. Glare (Failed)
  2. Violent Appearance
  3. Find the Law
  4. convolution
  5. 1004535809 upstairs question for tmd module changed WA3 times
  6. AC

Beating a watch really fragrant
But let's start with that general term
I don't understand the nature of this persimmon at all
Key property: When sum is recursive up, the interval decreases but does not increase
Clearly
So consider for a fixed r r r, a i a_i How much will ai contribute to it
Obviously, you can't move outward with k endpoints and the number of scenarios where the final (i.e., each) interval contains I
This means (1,i) selecting k weights for the left endpoint, (i,r) selecting k weights for the right endpoint.
Classic Repeatable Placement Count
Can be spicy

Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N=1e6+100;
const int mod= 1004535809; 
#define il inline
inline ll read(){
	ll x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-') f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
ll n,k;
ll A[N],B[N],r[N],lim,L;
ll ksm(ll x,ll k){
	ll res=1;
	while(k){
		if(k&1) res=res*x%mod;
		x=x*x%mod;
		k>>=1;
	}
	return res;
}
void ntt(ll *x,int flag){
	for(int i=0;i<lim;i++){
		if(i<r[i]) swap(x[i],x[r[i]]);
	}
	for(int l=1;l<lim;l<<=1){
		ll t0=ksm(3,(mod-1)/(l<<1));if(flag==-1) t0=ksm(t0,mod-2);
		for(int st=0;st<lim;st+=l<<1){
			ll t=1;
			for(int i=0;i<l;i++,t=t*t0%mod){
				ll u=x[st+i],v=t*x[st+i+l]%mod;
				x[st+i]=(u+v)%mod;
				x[st+i+l]=(u-v+mod)%mod;
			}
		}
	}
	if(flag==-1){
		ll ni=ksm(lim,mod-2);
		for(int i=0;i<lim;i++) x[i]=x[i]*ni%mod;
	}
}
ll f[N];
int main(){
	n=read();k=read();
	for(int i=1;i<=n;i++) A[i]=read()%mod;
	f[0]=1;
	for(int i=1;i<=n;i++) f[i]=f[i-1]*(k+i-1)%mod*ksm(i,mod-2)%mod;
	for(int i=1;i<=n;i++){
		A[i]=A[i]*f[i-1]%mod;
	}
	for(int i=0;i<=n;i++){
		B[i]=f[i];
	}
	lim=1;
	while(lim<n+n+2) lim<<=1,L++;
	for(int i=1;i<lim;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
	ntt(A,1);ntt(B,1);
	for(int i=0;i<lim;i++) A[i]=A[i]*B[i]%mod;
	ntt(A,-1);
	for(int i=1;i<=n;i++) printf("%lld ",A[i]);
	return 0;
}
/*
3 1 1
1 1 1
*/

summary

These beginners'polynomial questions are not really difficult after getting to the point.
But polynomials are really a long way to go...
I might start the system after noip
Time was plentiful then
Now it's time to focus on advanced content
Spicy, bye-bye~

Topics: number theory NTT