文章目錄
T1 多項式乘法(FFT)
板子
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
int i=0,f=1;char ch=0;
while(ch!='-'&&!isdigit(ch)) ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=1e7+5;
const double pi=acos(-1);
int n,m,rot[NNN];
struct Complex{
double x,y;
Complex(double _x=0,double _y=0){x=_x,y=_y;}
friend inline Complex operator + (const Complex u,const Complex v){return Complex(u.x+v.x,u.y+v.y);}
friend inline Complex operator - (const Complex u,const Complex v){return Complex(u.x-v.x,u.y-v.y);}
friend inline Complex operator * (const Complex u,const Complex v){return Complex(u.x*v.x-u.y*v.y,u.x*v.y+v.x*u.y);}
}A[NNN],B[NNN],C[NNN];
inline void FFT(Complex *f,int lim,int sgn){
for(int i=0;i<lim;++i)
if(i<rot[i]) swap(f[i],f[rot[i]]);
for(int siz=2;siz<=lim;siz<<=1){
int len=siz>>1;
Complex wn(cos(2*pi/siz),sgn*sin(2*pi/siz));
for(int l=0;l<lim;l+=siz){
Complex w(1,0);
for(int i=l;i<l+len;++i){
Complex tmp=w*f[i+len];
f[i+len]=f[i]-tmp;
f[i]=f[i]+tmp;
w=w*wn;
}
}
}
}
signed main(){
n=in,m=in;
for(int i=0;i<=n;++i) A[i].x=in;
for(int i=0;i<=m;++i) B[i].x=in;
int lim=1;
while(lim<=n+m) lim<<=1;
for(int i=0;i<lim;++i) rot[i]=((rot[i>>1]>>1)|((i&1)?lim>>1:0));
FFT(A,lim,1);
FFT(B,lim,1);
for(int i=0;i<=lim;++i) C[i]=A[i]*B[i];
FFT(C,lim,-1);
for(int i=0;i<=m+n;++i) printf("%lld ",(int)(C[i].x/lim+0.49));
return 0;
}
T2 A*B Problem升級版(FFT快速傅里葉)
注意最下面輸出答案的操作
#include<bits/stdc++.h>
using namespace std;
const int NNN=5e6+10;
const double pi=acos(-1);
int n,m,rev[NNN],ans[NNN];
char N[NNN],M[NNN];
struct Complex{
double x,y;
Complex(double xx=0,double yy=0){x=xx,y=yy;}
friend inline Complex operator + (const Complex &u,const Complex &v)
{return Complex(u.x+v.x,u.y+v.y);}
friend inline Complex operator - (const Complex &u,const Complex &v)
{return Complex(u.x-v.x,u.y-v.y);}
friend inline Complex operator * (const Complex &u,const Complex &v)
{return Complex(u.x*v.x-u.y*v.y,u.x*v.y+u.y*v.x);}
}A[NNN],B[NNN],C[NNN];
inline void FFT(Complex *f,int lim,int sgn){
for(int i=0;i<lim;++i)
if(i<rev[i]) swap(f[i],f[rev[i]]);
for(int siz=2;siz<=lim;siz<<=1){
int len=siz>>1;
Complex wn(cos(2*pi/siz),sgn*sin(2*pi/siz));
for(int l=0;l<lim;l+=siz){
Complex w(1,0);
for(int i=l;i<l+len;++i){
Complex tmp=f[i+len]*w;
f[i+len]=f[i]-tmp;
f[i]=f[i]+tmp;
w=w*wn;
}
}
}
}
int main(){
scanf("%s%s",N+1,M+1);
n=strlen(N+1);
m=strlen(M+1);
for(int i=1;i<=n;++i) A[n-i].x=(double)(N[i]-'0');--n;
for(int i=1;i<=m;++i) B[m-i].x=(double)(M[i]-'0');--m;
// for(int i=0;i<=n;++i) printf("%.2lf ",A[i].x);puts("");
// for(int i=0;i<=m;++i) printf("%.2lf ",B[i].x);puts("");
int lim=1;
while(lim<=n+m) lim<<=1;
for(int i=0;i<=lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?lim>>1:0);
FFT(A,lim,1);
FFT(B,lim,1);
for(int i=0;i<=lim;++i) C[i]=A[i]*B[i];
FFT(C,lim,-1);
for(int i=0;i<=lim;++i){
ans[i]+=(int)(C[i].x/lim+0.49);
if(ans[i]>=10){
ans[i+1]+=ans[i]/10;
ans[i]%=10;
lim+=(i==lim);
}
}
while(!ans[lim]&&lim>=1) --lim;
while(lim>=0) printf("%d",ans[lim]),--lim;
return 0;
}
T3 Force
定義當時值爲
定義且
其中爲卷積結果,可以FFT
對於
記,常見翻轉操作
也變成了卷積
設,則
有
對於,1.0/(i*i)
會被卡常,優化1.0/i/i
#include<bits/stdc++.h>
using namespace std;
const int NNN=5e5+5;
const double pi=acos(-1);
int n,rev[NNN];
double ans[NNN];
struct Complex{
double x,y;
Complex(double xx=0,double yy=0){x=xx,y=yy;}
friend inline Complex operator + (const Complex &u,const Complex &v){return Complex(u.x+v.x,u.y+v.y);}
friend inline Complex operator - (const Complex &u,const Complex &v){return Complex(u.x-v.x,u.y-v.y);}
friend inline Complex operator * (const Complex &u,const Complex &v){return Complex(u.x*v.x-u.y*v.y,u.x*v.y+u.y*v.x);}
}A[NNN],B[NNN],C[NNN],D[NNN],G[NNN];
inline void FFT(Complex *f,int lim,int sgn){
for(int i=0;i<=lim;++i)
if(i<rev[i]) swap(f[i],f[rev[i]]);
for(int siz=2;siz<=lim;siz<<=1){
int len=siz>>1;
Complex wn(cos(2*pi/siz),sgn*sin(2*pi/siz));
for(int l=0;l<lim;l+=siz){
Complex w(1,0);
for(int i=l;i<l+len;++i){
Complex tmp=w*f[i+len];
f[i+len]=f[i]-tmp;
f[i]=f[i]+tmp;
w=w*wn;
}
}
}
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i){
scanf("%lf",&A[i].x);
C[n-i].x=A[i].x;
B[i].x=(double)1.0/i/i;
}
// for(int i=1;i<=n;++i) printf("%.3lf,%.3lf,%.3lf\n",A[i].x,B[i].x,C[i].x);
int lim=1;
while(lim<=n+n) lim<<=1;
for(int i=0;i<=lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?lim>>1:0);
FFT(A,lim,1);
FFT(B,lim,1);
FFT(C,lim,1);
for(int i=0;i<=lim;++i) D[i]=B[i]*C[i],G[i]=A[i]*B[i];
FFT(D,lim,-1);
FFT(G,lim,-1);
for(int i=1;i<=n;++i) printf("%.3lf\n",G[i].x/lim-D[n-i].x/lim);
return 0;
}
T4 Gift
先說,這題的 m 告訴的是你最後增加亮度相對值 c 的上下界 [-m,m]
那麼我們一起推柿子
設增加亮度的相對值爲,旋轉後亮度數組爲
發現只有不確定(是關於的二次函數,可以回小學學一學最值的求法),於是最小化
常用的翻轉操作:
發現所求式中兩量下標/自變量同增,步長相等時,考慮翻轉一個,得到卷積
如,將翻轉,得到(卷積要保證下標和一定,且對稱)
注意邊界
破環爲鏈:倍長數組
#include<bits/stdc++.h>
using namespace std;
#define in Read()
#define int long long
inline int in{
int i=0,f=1;char ch=0;
while(ch!='-'&&!isdigit(ch)) ch=getchar();
if(ch=='-') ch=getchar(),f=-1;
while(isdigit(ch)) i=(i<<1)+(i<<3)+ch-48,ch=getchar();
return i*f;
}
const int NNN=5e5+5;
const int INF=1e15+5;
const double pi=acos(-1);
int n,m,ans=INF;
int a[NNN],b[NNN];
int sqr_a,sqr_b;
int sum_a,sum_b;
int rev[NNN];
struct Complex{
double x,y;
Complex(double xx=0,double yy=0){x=xx,y=yy;}
friend inline Complex operator + (const Complex &u,const Complex &v)
{return Complex(u.x+v.x,u.y+v.y);}
friend inline Complex operator - (const Complex &u,const Complex &v)
{return Complex(u.x-v.x,u.y-v.y);}
friend inline Complex operator * (const Complex &u,const Complex &v)
{return Complex(u.x*v.x-u.y*v.y,u.x*v.y+u.y*v.x);}
}A[NNN],B[NNN];
inline void FFT(Complex *f,int lim,int sgn){
for(int i=0;i<=lim;++i)
if(i<rev[i]) swap(f[i],f[rev[i]]);
for(int siz=2;siz<=lim;siz<<=1){
int len=siz>>1;
Complex wn(cos(2*pi/siz),sgn*sin(2*pi/siz));
for(int l=0;l<lim;l+=siz){
Complex w(1,0);
for(int i=l;i<l+len;++i){
Complex tmp=f[i+len]*w;
f[i+len]=f[i]-tmp;
f[i]=f[i]+tmp;
w=w*wn;
}
}
}
}
signed main(){
n=in,m=in;
for(int i=1;i<=n;++i){
a[i]=in;
A[i].x=A[i+n].x=(double)a[i];
sqr_a+=a[i]*a[i];
sum_a+=a[i];
}
for(int i=1;i<=n;++i){
b[i]=in;
B[n-i+1].x=(double)b[i];
sqr_b+=b[i]*b[i];
sum_b+=b[i];
}
int lim=1;
while(lim<=n*3) lim<<=1;
for(int i=0;i<=lim;++i) rev[i]=(rev[i>>1]>>1)|((i&1)?(lim>>1):0);
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<=lim;++i) A[i].x=(int)(A[i].x/lim+0.49);
for(int i=1;i<=n;++i)
for(int x=-m;x<=m;++x){
int tmp=n*x*x+sqr_a+sqr_b;
tmp+=2*(sum_a-sum_b)*x;
ans=min(ans,tmp-2*(int)A[i+n].x);
}
printf("%lld\n",ans);
return 0;
}