# ZOJ3856 Goldbach[FFT]

## K - Goldbach

ZOJ - 3856

ans[i]=ans[i]+1   ans[i*3]=ans[i*3]+1;

①a*b

ans[a*b]=ans[a*b]+1

②a*b+c

ans[i]=ans[i]+res[i]   res[i]为当前多项式计算结果

③a*b*c

ans[a*b*c]=ans[a*b*c]+1

①a+b

ans[i]=ans[i]+res[i]  res[i]为当前多项式计算结果

②a+b+c

a+b+c如果 a、b、c取值都不一样的话，那么会有三种情况 a+b+c、a+c+b、b+c+a 要得到结果我们只需要将这个方案数/3即可

ans[i]=ans[i]+(res[i]+tmp[i]*2)/3   res[i]为三种取值不同和第一次加法时去掉相同的数相加的情况 tmp为2*a+b的结果

#pragma comment(linker, "/STACK:102400000,102400000")
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<set>
#include<map>
#include<vector>
using namespace std;
typedef long long ll;
const double PI=acos(-1.0);
const int N=8e4+5;
const int M=1<<18;
const int mod=1e9+7;
bool mark[N];
int prim[N];
int cnt;
ll ans[N],res[M],tmp[M];
struct Complex
{
double real,image;
Complex(double r=0.0,double i=0.0):real(r),image(i){}
Complex operator + (const Complex &b)
{
return Complex(real+b.real,image+b.image);
}
Complex operator - (const Complex &b)
{
return Complex (real-b.real,image-b.image);
}
Complex operator * (const Complex &b)
{
return Complex (real*b.real-image*b.image,image*b.real+real*b.image);
}
}a[M],b[M];
void change(Complex x[],int len)
{
for (int i=1,j=len/2 ; i<len-1 ; ++i)
{
if (i<j)
swap(x[i],x[j]);
int k=len/2;
while (j>=k)
{
j-=k;
k/=2;
}
if (j<k)
j+=k;
}
}
void FFT(Complex x[],int len,int dft)
{
change(x,len);
for (int h=2 ; h<=len ; h<<=1)
{
Complex wn(cos(2*PI*dft/h),sin(2*PI*dft/h));
for (int j=0 ; j<len ; j+=h)
{
Complex w(1,0);
for (int k=j ; k<j+h/2 ; ++k)
{
Complex u=x[k];
Complex t=w*x[k+h/2];
x[k]=u+t;
x[k+h/2]=u-t;
w=w*wn;
}
}
}
if (dft==-1)
{
for (int i=0 ; i<len ; ++i)
{
x[i].real/=len;
x[i].image/=len;
}
}
}
{
memset(res,0,sizeof(res));
for (int i=0 ; i<cnt && prim[i]<=sqrt(N) ; ++i)//两个数相乘等于x
{
for (int j=i ; j<cnt ; ++j)
{
if ((ll)prim[i]*prim[j]>=(ll)N)
break;
res[prim[i]*prim[j]]++;
ans[prim[i]*prim[j]]=(ans[prim[i]*prim[j]]+1)%mod;
}
}
for (int i=0 ; i<len ; ++i)
{
if (i<N)
{
a[i]=Complex(res[i],0);
b[i]=Complex(!mark[i],0);
}
else
a[i]=b[i]=Complex(0,0);
}

FFT(a,len,1);
FFT(b,len,1);
for (int i=0 ; i<len ; ++i)
a[i]=a[i]*b[i];
FFT(a,len,-1);
for (int i=0 ; i<len ; ++i)
res[i]=(ll)(a[i].real+0.5);
for (int i=0 ; i<N ; ++i)
ans[i]=(ans[i]+res[i]%mod)%mod;
}
{
for (int i=0 ; i<len ; ++i)
{
if (i<N)
a[i]=b[i]=Complex(!mark[i],0);
else
a[i]=b[i]=Complex(0,0);
}
FFT(a,len,1);
for (int i=0 ; i<len ; ++i)
a[i]=a[i]*a[i];
FFT(a,len,-1);
for (int i=0 ; i<len ; ++i)//;两个相加
{
res[i]=(ll)(a[i].real+0.5);
res[i]=res[i]&1?(res[i]+1)/2:res[i]/2;//去掉两个相加的时候的重复计算
}
for (int i=0 ; i<N ; ++i)
ans[i]=(ans[i]+res[i]%mod)%mod;
for (int i=0 ; i<len ; ++i)
res[i]=(ll)(a[i].real+0.5);
for (int i=0 ; i<cnt ; ++i)//去掉自身相加的结果
res[prim[i]+prim[i]]--;
for (int i=0 ; i<len ; ++i)//去掉两个相加的时候的重复计算
res[i]/=2;
for (int i=0 ; i<len ; ++i)
{
if (i<N)
a[i]=Complex(res[i],0);
else
a[i]=Complex(0,0);
}
FFT(a,len,1);
FFT(b,len,1);
for (int i=0 ; i<len ; ++i)//三个相加
a[i]=a[i]*b[i];
FFT(a,len,-1);
for (int i=0 ; i<len ; ++i)
res[i]=(ll)(a[i].real+0.5);
for (int i=0 ; i<len ; ++i)
{
if (i<N)
a[i]=Complex(!mark[i],0);
else
a[i]=Complex(0,0);
b[i]=Complex(0,0);
}
for (int i=0 ; i<cnt ; ++i)
if (prim[i]*2<N)
b[prim[i]*2]=Complex(1,0);
FFT(a,len,1);
FFT(b,len,1);
for (int i=0 ; i<len ; ++i)//两个重复的加上另外一个数
a[i]=a[i]*b[i];
FFT(a,len,-1);
for (int i=0 ; i<len ; ++i)
tmp[i]=(ll)(a[i].real+0.5);
for (int i=0 ; i<len ; ++i)
res[i]=(res[i]+tmp[i]*2)/3;
for (int i=0 ; i<N ; ++i)
ans[i]=(ans[i]+res[i]%mod)%mod;
}
void threemul()//三个相乘的情况
{
for (int i=0 ; i<cnt ; ++i)
{
bool flag=0;
for (int j=i ; j<cnt ; ++j)
{
if ((ll)prim[i]*prim[j]>(ll)N)
break;
for (int k=j ; k<cnt ; ++k)
{
if (i==j && k==j && (ll)prim[i]*prim[j]*prim[k]>(ll)N)
{
flag=1;
break;
}
if ((ll)prim[i]*prim[j]*prim[k]>N)
break;
ans[prim[i]*prim[j]*prim[k]]=(ans[prim[i]*prim[j]*prim[k]]+1)%mod;
}
if ((ll)prim[i]*prim[j]*prim[j]>=(ll)N || flag)
break;
}
if (flag)
break;
}
}
void initial()
{
cnt=0;
mark[0]=mark[1]=1;
memset(ans,0,sizeof(ans));
for (int i=2 ; i<N ; ++i)
{
if (!mark[i])
{
prim[cnt++]=i;
ans[i]=(ans[i]+1)%mod;//当前数为素数(即用一个数)
if (i*3<N)
ans[i*3]=(ans[i*3]+1)%mod;//三个相同的数相加
}
for (int j=0 ; j<cnt && i*prim[j]<N ; ++j)
{
mark[i*prim[j]]=1;
if (!(i%prim[j]))
break;
}
}
int len=1;
while (len<(N<<1))
len<<=1;
threemul();
}
int main()
{
initial();
int x;
while (~scanf("%d",&x))
{
printf("%lld\n",ans[x]);
}
return 0;
}