题意:0~9种有k种可用数字,求前n/2个数字和与后n/2个数字和相等的方案数。
这题继续刷新我对多项式(常数)的认识。。。。。。
不难发现这个题就是多项式快速幂。。。。。。
然后我就想尝试一下新打的多项式
的版,
是不是很资瓷啊。
然后极限数据连多项式求逆都要跑
更不要说什么exp了。
正解居然是NTT一次然后对NTT后的数组每一个数
变为
然后再NTT回来这种操作。
其实早就想过这种操作了,可是碍于网上的代码都不这么写,就没怎么想。
今天来一发我自己的理解。
上面的那个操作是正确的,多项式系列算法其实有两个mod,一个是题目给的998244353,还有一个就是答案多项式是在
下计算的,不然项数可能会爆炸。
如果题目的答案需要mod任意一个mod,那么都不能NTT一次最后再NTT回来,因为中途你得NTT回来mod(如果mod的不是998244353,那么得需要拆系数FFT或3模数来保证不会炸long double / LL , 如果需要mod x^n , 那么得需要NTT回来把
以上的项全部清为0,不然NTT会变成循环卷积的,你的多项式求逆,求
,求
都是在这个意义下才成立的)。
所以如果是一个长度为 的多项式的 次幂 ,那么你NTT一次最后再NTT回来时你得开 的数组才能保证NTT不会变成循环卷积。。。。只能每次都NTT过去再NTT回来 ,或者多项式
而这个题是长度为10的多项式的 次幂,当然可以(小常数) 的只NTT两次啦。
AC Code;
#include<bits/stdc++.h>
#define maxn (1<<21)+5
#define mod 998244353
using namespace std;
int r[maxn],inv[maxn]={1,1},w[maxn]={1},lg[maxn],wlen;
int Pow(int base,int k)
{ int ret = 1;
for(;k;k>>=1,base=1ll*base*base%mod) if(k&1) ret=1ll * ret* base % mod;
return ret;}
void Init(int n)
{ for(wlen=1;n>=(wlen<<1);wlen<<=1);
for(int i=1,pw=Pow(3,(mod-1)/(2*wlen));i<=2*wlen;i++) w[i] = 1ll * w[i-1] * pw % mod;
for(int i=2;i<=2*wlen;i++)
lg[i] = lg[i>>1] + 1, inv[i] = 1ll * (mod - mod / i) * inv[mod % i] % mod;}
inline void NTT(int A[maxn],int n,int tp)
{ int lgn = lg[n];
for(int i=1;i<n;i++) r[i]=(r[i>>1]>>1)|((i&1)<<(lgn-1));
for(int i=1;i<n;i++) if(i<r[i]) swap(A[i],A[r[i]]);
for(int L=2;L<=n;L<<=1)
for(int st=0,l=L>>1,inc=wlen/l;st<n;st+=L)
for(int k=st,x=0,tmp;k<st+l;k++,x+=inc)
tmp=1ll*(tp==1?w[x]:w[2*wlen-x])*A[k+l]%mod,
A[k+l]=(A[k]-tmp)%mod,A[k]=(A[k]+tmp)%mod;
if(tp==-1) for(int i=0,inv=Pow(n,mod-2);i<n;i++) A[i]=1ll*A[i]*inv%mod;
}
void Inv(int *A,int *B,int n)
{ B[0]=Pow(A[0],mod-2),B[1]=0;
static int tmp[maxn];
for(int k=2;k<(n<<1);k<<=1)
{ for(int i=0;i<(k<<1);i++) tmp[i]=i<k?A[i]:0,B[i]=i<k?B[i]:0;
NTT(tmp,k<<1,1),NTT(B,k<<1,1);
for(int i=0;i<(k<<1);i++) B[i]=1ll*B[i]*(2-1ll*B[i]*tmp[i]%mod)%mod;
NTT(B,k<<1,-1);for(int i=min(n,k);i<(k<<1);i++) B[i]=0;}
}
void cLn(int *A,int *B,int n)
{ Inv(A,B,n);
static int tmp[maxn];
int lgn=lg[n-1]+2,len=1<<lgn;
for(int i=0;i<len;i++) tmp[i]=i<n-1?1ll*A[i+1]*(i+1)%mod:0,B[i]=i<n?B[i]:0;
NTT(tmp,len,1),NTT(B,len,1);
for(int i=0;i<len;i++) tmp[i]=1ll*tmp[i]*B[i]%mod;
NTT(tmp,len,-1);B[0]=0;
for(int i=1;i<n;i++) B[i]=1ll*tmp[i-1]*inv[i]%mod;
for(int i=n;i<len;i++) B[i] = 0;
}
void eXp(int *A,int *B,int n)
{ B[0]=1,B[1]=0;
static int tmp[maxn];
for(int k=2;k<(n<<1);k<<=1)
{ cLn(B,tmp,k);
for(int i=0;i<(k<<1);i++) tmp[i]=i<k?((i==0)-tmp[i]+A[i])%mod:0,B[i]=i<k?B[i]:0;
NTT(tmp,k<<1,1),NTT(B,k<<1,1);
for(int i=0;i<(k<<1);i++) B[i]=1ll*B[i]*tmp[i]%mod;
NTT(B,k<<1,-1);for(int i=min(n,k);i<(k<<1);i++) B[i] = 0;
}
}
void Pow(int *A,int *B,int n,int k)
{ int lgn = lg[n-1]+2 , len = 1 << lgn;
for(int i=0;i<len;i++) B[i] = i<n?A[i]:0;
NTT(B,len,1);
for(int i=0;i<len;i++) B[i]=Pow(B[i],k);
NTT(B,len,-1);
}
int a[maxn],b[maxn];
int main()
{
int n,k,d[20]={};
scanf("%d%d",&n,&k);
for(int i=0;i<k;i++) scanf("%d",&d[i]);
sort(d,d+k);
for(int i=0;i<k;i++) a[d[i]-d[0]]++;
int tp = d[k-1] - d[0];
Init(n*10);
Pow(a,b,n/2*tp+1,n/2);
int ans = 0;
for(int i=0;i<n*5;i++)
ans = (ans + 1ll * b[i] * b[i] % mod) % mod;
printf("%d\n",(ans+mod)%mod);
}