小C有一个集合S,里面的元素都是小于M的非负整数。他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S。
小C用这个生成器生成了许多这样的数列。但是小C有一个问题需要你的帮助:给定整数x,求所有可以生成出的,且满足数列中所有数的乘积mod M的值等于x的不同的数列的有多少个。小C认为,两个数列{Ai}和{Bi}不同,当且仅当至少存在一个整数i,满足Ai≠Bi。另外,小C认为这个问题的答案可能很大,因此他只需要你帮助他求出答案mod 1004535809的值就可以了。
FFT/NNT练习题目
解法是先把暴力Dp式子写出来,因为里面有乘法,把乘法转成幂次的加,这样就变成了多项式乘法了,
当然要求原根
复杂度: O(log(N)∗Mlog(M))
#include
#define fo(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
typedef long long LL;
const int N=8500,mo=1004535809;
int read(int &n)
{
char ch=' ';int q=0,w=1;
for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
if(ch=='-')w=-1,ch=getchar();
for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,n1,m1,R;
int a[N];
LL ans;
LL f[N*4],Ans[N*4],c[N*4];
LL W[N*4],W0,niy;
LL ksm(LL q,int w,int MO=mo)
{
LL ans=1;q%=MO;
for(;w;w>>=1,q=q*q%MO)if(w&1)ans=ans*q%MO;
return ans;
}
LL ROK(int q,int n)
{
int w=n-1;
for(int i=2;i*i<=w;++i)if(w%i==0)
{
for(;w%i==0;w=w/i);
if(1==ksm(q,(n-1)/i,n))return 0;
}
if(w-1)return 1!=ksm(q,(n-1)/w,n);
return 1;
}
void DFT(LL *a,int n,int ws,int K)
{
fo(i,0,n-1)
{
int q=0;
for(int j=i,w=ws;w;w--,j>>=1)q=(q<<1)+(j&1);
c[q]=a[i];
}
for(int I=2;I<=n;I<<=1)
{
int mid=I>>1;
fo(i,0,mid-1)
{
LL w=(K>0)?(W[W0/I*i]):(W[W0-W0/I*i]);
for(int j=i;j*c[j+mid]%mo;
c[j+mid]=(c[j]-t)%mo;
c[j]=(c[j]+t)%mo;
}
}
}
if(K<0)fo(i,0,n-1)c[i]=c[i]*niy%mo;
}
void FFTpre()
{
int m,ws;
for(m=1,ws=1;mm<<=1,ws++);
m<<=1;
DFT(f,m,ws,1);
fo(i,0,m)f[i]=c[i]*c[i]%mo;
DFT(f,m,ws,-1);
fo(i,0,n-1)f[i]=c[i];
fo(i,n,m)f[i%n]=(f[i%n]+c[i])%mo,f[i]=0;
}
void FFT()
{
int m,ws;
for(m=1,ws=1;mm<<=1,ws++);
m<<=1;
DFT(Ans,m,ws,1);
fo(i,0,m)Ans[i]=c[i];
DFT(f,m,ws,1);
fo(i,0,m)Ans[i]=Ans[i]*c[i]%mo;
DFT(Ans,m,ws,-1);
fo(i,0,n-1)Ans[i]=c[i];
fo(i,n,m)Ans[i%n]=(Ans[i%n]+c[i])%mo,Ans[i]=0;
}
void ksm(int w)
{
Ans[0]=1;
for(;w;w>>=1,FFTpre())if(w&1)FFT();
}
int main()
{
freopen("!.in","r",stdin);
// freopen(".out","w",stdout);
int q;
read(n1),read(n),read(m),read(m1);
fo(i,1,m1)a[read(q)%n]++;
fo(i,2,n-1)if(ROK(i,n)){R=i;break;}
--n;q=1;
fo(i,0,n-1)f[i]=a[q],q=q*R%(n+1);
for(W0=1;W00<<=1);W0<<=1;
W[0]=1;W[1]=ksm(3,(mo-1)/W0);niy=ksm(W0,mo-2);
fo(i,2,W0)W[i]=W[i-1]*W[1]%mo;
ksm(n1);
ans=0;
q=1;
fo(i,0,n-1)
{
if(q==m)ans+=Ans[i];
q=q*R%(n+1);
}
printf("%lld\n",(ans+mo)%mo);
return 0;
}