题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=3456

题解

n个点构成的连通图数量为

g(n)=2(n2)

枚举1号点所在连通块的大小,得到
gn=i=1n(n1i1)figni

因此
2(n2)=i=1n(n1)!(i1)!(ni)!figni

整理得到
2(n2)(n1)!=i=1nfi(i1)!2(ni2)(ni)!


F=fi(i1)!xi,G=2(i2)i!xi,T=2(i2)(i1)!xi

则有
T=FG(modxn+1)


F=TG1(modxn+1)

先求出GT,求G的逆元,卷积一遍就可以得到F,得到F之后很容易得到fi

代码

#include <cstdio>
#include <cstring>
#include <algorithm>

int read()
{
  int x=0,f=1;
  char ch=getchar();
  while((ch<'0')||(ch>'9'))
    {
      if(ch=='-')
        {
          f=-f;
        }
      ch=getchar();
    }
  while((ch>='0')&&(ch<='9'))
    {
      x=x*10+ch-'0';
      ch=getchar();
    }
  return x*f;
}

const int maxn=300000;
const int mod=1004535809;
const int G=3;

int quickpow(int a,int b,int m)
{
  int res=1;
  while(b)
    {
      if(b&1)
        {
          res=1ll*res*a%m;
        }
      a=1ll*a*a%m;
      b>>=1;
    }
  return res;
}

int plus(int a,int b,int m)
{
  int res=a+b;
  if(res>=m)
    {
      res-=m;
    }
  return res;
}

int minus(int a,int b,int m)
{
  int res=a-b;
  if(res<0)
    {
      res+=m;
    }
  return res;
}

int rev[maxn+10],tmp[maxn+10];

int getrev(int n)
{
  int m=1,len=0;
  while(m<=n)
    {
      m<<=1;
      ++len;
    }
  for(int i=0; i<m; ++i)
    {
      rev[i]=(rev[i>>1]>>1)+((i&1)<<(len-1));
    }
  return m;
}

int fft(int *s,int len)
{
  for(int i=0; i<len; ++i)
    {
      if(rev[i]<i)
        {
          std::swap(s[rev[i]],s[i]);
        }
    }
  for(int i=2; i<=len; i<<=1)
    {
      int gn=quickpow(G,(mod-1)/i,mod);
      for(int j=0; j<len; j+=i)
        {
          int g=1;
          for(int k=0; k<(i>>1); ++k)
            {
              int x=s[j+k],y=1ll*g*s[j+k+(i>>1)]%mod;
              s[j+k]=plus(x,y,mod);
              s[j+k+(i>>1)]=minus(x,y,mod);
              g=1ll*g*gn%mod;
            }
        }
    }
  return 0;
}

int getinv(int *s,int *v,int deg)
{
  if(deg==1)
    {
      v[0]=quickpow(s[0],mod-2,mod);
      return 0;
    }
  getinv(s,v,(deg+1)>>1);
  int p=getrev(deg<<1);
  for(int i=0; i<deg; ++i)
    {
      tmp[i]=s[i];
    }
  for(int i=deg; i<p; ++i)
    {
      tmp[i]=0;
    }
  fft(tmp,p);
  fft(v,p);
  for(int i=0; i<p; ++i)
    {
      v[i]=1ll*v[i]*minus(2,1ll*tmp[i]*v[i]%mod,mod)%mod;
    }
  fft(v,p);
  std::reverse(v+1,v+p);
  int fk=quickpow(p,mod-2,mod);
  for(int i=0; i<p; ++i)
    {
      v[i]=1ll*v[i]*fk%mod;
    }
  for(int i=deg; i<p; ++i)
    {
      v[i]=0;
    }
  return 0;
}

int n,g[maxn+10],t[maxn+10],fac[maxn+10],ig[maxn+10],ifac[maxn+10];

int main()
{
  n=read();
  fac[0]=1;
  for(int i=1; i<=n; ++i)
    {
      fac[i]=1ll*i*fac[i-1]%mod;
    }
  ifac[n]=quickpow(fac[n],mod-2,mod);
  for(int i=n-1; i; --i)
    {
      ifac[i]=1ll*ifac[i+1]*(i+1)%mod;
    }
  ifac[0]=1;
  for(int i=1; i<=n; ++i)
    {
      int v=quickpow(2,((1ll*(i-1)*i)/2)%(mod-1),mod);
      g[i]=1ll*v*ifac[i]%mod;
      t[i]=1ll*v*ifac[i-1]%mod;
    }
  g[0]=1;
  getinv(g,ig,n+1);
  int m=getrev(n<<1);
  fft(t,m);
  fft(ig,m);
  for(int i=0; i<m; ++i)
    {
      g[i]=1ll*t[i]*ig[i]%mod;
    }
  fft(g,m);
  std::reverse(g+1,g+m);
  int fk=quickpow(m,mod-2,mod);
  for(int i=0; i<m; ++i)
    {
      g[i]=1ll*g[i]*fk%mod;
    }
  printf("%lld\n",1ll*g[n]*fac[n-1]%mod);
  return 0;
}