bzoj3684 大朋友的多叉树

Description

我们的大朋友很喜欢计算机科学,而且尤其喜欢多叉树。对于一棵带有正整数点权的有根多叉树,如果它满足这样的性质,我们的大朋友就会将其称作神犇的:点权为1的结点是叶子结点;对于任一点权大于1的结点u,u的孩子数目deg[u]属于集合D,且u的点权等于这些孩子结点的点权之和。
给出一个整数s,你能求出根节点权值为s的神犇多叉树的个数吗?请参照样例以更好的理解什么样的两棵多叉树会被视为不同的。
我们只需要知道答案关于950009857(453*2^21+1,一个质数)取模后的值。

 

Input

第一行有2个整数s,m。
第二行有m个互异的整数,d[1],d[2],…,d[m],为集合D中的元素。

 

Output

输出一行仅一个整数,表示答案模950009857的值。

 

Sample Input

4 2
2 3

Sample Output

10

HINT

数据规模:

1<=m<s<=10^5, 2<=d[i]<=s,有3组小数据和3组大数据。
 
 
 
 
获得新知识:拉格朗日反演

不知道怎么证

结论还是比较好记的

获得新模板:fft的基本操作

//%std
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
#include<stack>
#include<set>
#include<map>
using namespace std;
#define lovelive long long
#define lc son[x][0]
#define rc son[x][1]
#define lowbit(x) (x&(-x))
#define pt vc
const lovelive mod=950009857,G=7;
const int N=1e5+100;
void read(lovelive &x)
{
  lovelive p=1;
  x=0;
  char c=getchar();
  while(c<'0'||c>'9')
  {
    if(c=='-')
      p=-1;
    c=getchar();
  }
  while(c>='0'&&c<='9')
  {
      x=x*10+c-48;
      c=getchar();
  }
  x*=p;
}
lovelive A[N<<2],B[N<<2],tmp[N<<2],f[N<<2],g[N<<2];
lovelive pow1(lovelive x,lovelive k)
{
  lovelive r=1;
  if(k<0)
    k+=mod-1;
  while(k)
  {
   if(k&1)
     r*=x;
   x*=x;
   r%=mod;
   x%=mod;
   k>>=1;
  }
  return r;
}
void change(lovelive y[],int len)
{
  for(lovelive i=1,j=len>>1,k;i<len-1;i++)
  {
    if(i<j)
      swap(y[i],y[j]);
    k=len>>1;
    while(j>=k)
    {
      j-=k;
      k>>=1;  
    } 
    if(j<=k)
      j+=k;
  }
}
void fft(lovelive y[],int len,int on)
{
  change(y,len);
  for(int h=2;h<=len;h<<=1)
  {
    lovelive wn=pow1(G,(mod-1)*on/h);
    for(int j=0;j<len;j+=h)
    {
      lovelive w=1;
      for(int i=j;i<j+(h>>1);i++)
      {
        lovelive u=y[i],v=w*y[i+(h>>1)]%mod;
        y[i]=(u+v)%mod;
        y[i+(h>>1)]=(u-v+mod)%mod;
        w=w*wn%mod;
      }
    }
  }
  if(on==-1)
  {
    lovelive inv=pow1(len,-1);
    for(int i=0;i<len;i++)
      y[i]=y[i]*inv%mod;
  }
}
void find_inv(lovelive a[],lovelive b[],int len)
{
  if(len==1)
  {
    b[0]=pow1(a[0],-1);b[1]=0;
    return;
  }
  find_inv(a,b,len>>1);
  for(int i=0;i<len;i++)
    f[i]=a[i];
  memcpy(f,a,sizeof(b[0])*len);
  memset(f+len,0,sizeof(f[0])*len);
  fft(f,len<<1,1);
  fft(b,len<<1,1);
  for(int i=0;i<len<<1;i++)
    f[i]=b[i]*(2+mod-f[i]*b[i]%mod)%mod;
  fft(f,len<<1,-1);
  for(int i=0;i<len;i++)
    b[i]=f[i];
  memset(b+len,0,sizeof(b[0])*len);
  return;
}
lovelive inv[N<<2],jc[N<<2];
void find_ln(lovelive a[],lovelive b[],int len)
{
//  for(int i=0;i<len;i++)
//    g[i]=0;
  find_inv(a,g,len);
  for(lovelive i=0;i<len-1;i++)
    b[i]=a[i+1]*(i+1)%mod;
//  b[len]=0;
  fft(g,len<<1,1);
  fft(b,len<<1,1);
  for(int i=0;i<len<<1;i++)
    b[i]=b[i]*g[i]%mod;
  fft(b,len<<1,-1);
  for(int i=len-1;i;i--)
    b[i]=b[i-1]*(inv[i]*jc[i-1]%mod)%mod;
  b[0]=0;
  memset(b+len,0,sizeof(b[0])*len);
  memset(g,0,sizeof(g[0])*len<<1);
}
void find_exp(lovelive a[],lovelive b[],int len)
{
  if(len==1)
  {
    b[0]=1;b[1]=0;
    return;
  }
  find_exp(a,b,len>>1);
  memset(tmp,0,sizeof(tmp[0])*len<<1);
  find_ln(b,tmp,len);
  for(int i=0;i<len;i++)
    tmp[i]=((i==0)+(mod-tmp[i])+a[i])%mod;
  fft(b,len<<1,1);
  fft(tmp,len<<1,1);
  for(int i=0;i<len<<1;i++)
    b[i]=b[i]*tmp[i]%mod; 
  fft(b,len<<1,-1);
  for(int i=0;i<len;i++)
    b[i+len]=0;
  return;
}
void prepare(int len)
{
  jc[0]=inv[0]=1;
  for(lovelive i=1;i<=len;i++)
    jc[i]=jc[i-1]*i%mod;
  inv[len]=pow1(jc[len],-1);
  for(lovelive i=len-1;i>=0;i--)
    inv[i]=inv[i+1]*(i+1)%mod;
}
lovelive C[N<<2];
void find_kth(lovelive a[],lovelive b[],lovelive k,int len)
{
  find_ln(a,C,len);
  for(int i=0;i<len;i++)
    C[i]=C[i]*k%mod;
  find_exp(C,b,len);
}
int main()
{
  lovelive n,s,x,len=1;
  read(s);read(n);
  for(int i=1;i<=n;i++)
  {
    read(x);
    A[x-1]=mod-1;
  }
  A[0]++;
  while(len<=s)
    len<<=1;
  prepare(len);
  find_inv(A,B,len);
  memset(A,0,sizeof(A));
  find_kth(B,A,s,len);
  cout<<A[s-1]*pow1(s,-1)%mod<<"\n";
//  read(n);
//  for(int i=0;i<=n;i++)
//    read(A[i]);
//  while(len<=n)
//    len<<=1;
//  prepare(len);
//  find_exp(A,B,len);
//  for(int i=0;i<=n;i++)
//    printf("%lld ",B[i]);
  return 0;
}
/*
3 2
2 3

4 3
2 3 4

100000 4
2 3 4 5
*/
View Code

 

 
posted @ 2018-04-26 20:25  NicoDafaGood  阅读(168)  评论(0编辑  收藏  举报