传送门
题目大意:有M种氨基酸,每个的相对分子质量为Ci,问组合出的肽链水解之后有多少个相对分子质量和为N(排列)。
选的氨基酸的数量不限。
一个比较显然的思路是对于每一种氨基酸搞一个生成函数出来,也就是x^(Ci的倍数)项的系数为1,然后把M个卷起来就行了
但是这样复杂度是 O(MNlogN) 的,并且没法加速
换一种思路…
将所有的氨基酸搞成一个生成函数,x^k的系数为相对分子质量为k的氨基酸有多少个,设为 A(x)
那么其实就是这样一个卷积
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
#define Mod 1005060097
#define N 600005
int sum,cnt,Max,n,m,L,R[N];
LL a[N],b[N],c[N];
LL fast_pow(LL a,int p)
{
LL ans=1;
for (;p;p>>=1,a=a*a%Mod)
if (p&1)
ans=ans*a%Mod;
return ans;
}
void NTT(LL a[N],int n,int opt)
{
L=0;for (int i=1;i1) ++L;
for (int i=0;i<=n;++i)
R[i]=(R[i>>1]>>1)|((i&1)<<(L-1));
for (int i=0;iif (ifor (int k=1;k1)
{
LL wn=fast_pow(5,(Mod-1)/(k<<1));
for (int i=0;i1))
{
LL w=1;
for (int j=0;j*wn%Mod)
{
LL x=a[i+j],y=w*a[i+j+k]%Mod;
a[i+j]=(x+y)%Mod,a[i+j+k]=(x-y+Mod)%Mod;
}
}
}
if (opt==-1) reverse(a+1,a+n);
}
void inverse(int n,LL a[N],LL b[N],LL c[N])
{
if (n==1) b[0]=fast_pow(a[0],Mod-2);
else
{
inverse(n>>1,a,b,c);
int k=n<<1;
for (int i=0;ifor (int i=n;i0;
NTT(c,k,1);NTT(b,k,1);
for (int i=0;i2-c[i]*b[i]%Mod+Mod)%Mod*b[i]%Mod;
NTT(b,k,-1);
LL inv=fast_pow(k,Mod-2);
for (int i=0;i*inv%Mod;
for (int i=n;i0;
}
}
int main()
{
freopen("polypeptide.in","r",stdin);
freopen("polypeptide.out","w",stdout);
scanf("%d%d",&sum,&cnt);++a[0];
for (int i=1;i<=cnt;++i)
{
int x;scanf("%d",&x);
--a[x];Max=max(Max,x);
}
m=Max<<1;
for (n=1;n<=m;n<<=1) ++L;
for (int i=0;i<=n;++i) a[i]=(a[i]+Mod)%Mod;
inverse(n,a,b,c);
printf("%lld\n",b[sum]);
}