题目链接

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

题解

考虑求非强连通子图的数量,假设为gg,那么答案就是2mg2^m-g。现在考虑求gg

假设fsf_s表示用ss这些点能构成的强连通图的个数,gsg_s表示用ss这些点能构成的非强连通图的方案数,其中构成ii个强连通分量则对gsg_s的贡献为(1)i(-1)^i。容易发现
gs=fsts,utgtfst g_s=f_s-\sum_{t\subset s,u\in t} g_tf_{s-t}
那么
fs=2ests,t̸=2est+est,tgs f_s=2^{e_s}-\sum_{t\subseteq s,t\not= \varnothing}2^{e_{s-t}+e_{s-t,t}}g_s
容易发现,fsf_s此时需要的是不包含fsf_sgsg_s,因此gsg_s在求出fsf_s之前是不能+fs+f_s的。

代码

#include <cstdio>
 
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=15;
const int maxm=1<<maxn;
const int mod=1000000007;
 
int n,m,f[maxm+10],g[maxm+10],pow[maxn*maxn+10],ecnt[maxm+10][maxn+2],in[maxm+10];
 
inline int lowbit(int x)
{
  return x&(-x);
}
 
int main()
{
  n=read();
  m=read();
  int full=(1<<n)-1;
  for(int i=1; i<=m; ++i)
    {
      int a=read(),b=read();
      for(int j=1; j<=full; ++j)
        {
          if((1<<(a-1))&j)
            {
              ++ecnt[j][b];
            }
        }
    }
  pow[0]=1;
  for(int i=1; i<=m; ++i)
    {
      pow[i]=pow[i-1]<<1;
      if(pow[i]>=mod)
        {
          pow[i]-=mod;
        }
    }
  f[0]=g[0]=1;
  for(int s=1; s<=full; ++s)
    {
      int sk=s^lowbit(s);
      for(int t=sk; t; t=sk&(t-1))
        {
          g[s]-=1ll*f[s^t]*g[t]%mod;
          if(g[s]<0)
            {
              g[s]+=mod;
            }
        }
      for(int i=1; i<=n; ++i)
        {
          if((1<<(i-1))&s)
            {
              in[s]+=ecnt[s][i];
            }
        }
      f[s]+=pow[in[s]];
      for(int t=s; t; t=s&(t-1))
        {
          int e=0;
          for(int i=1; i<=n; ++i)
            {
              if((1<<(i-1))&t)
                {
                  e+=ecnt[s^t][i];
                }
            }
          f[s]-=1ll*pow[e+in[s^t]]*g[t]%mod;
          if(f[s]<0)
            {
              f[s]+=mod;
            }
        }
      g[s]+=f[s];
      if(g[s]>=mod)
        {
          g[s]-=mod;
        }
    }
  printf("%d\n",f[full]);
  return 0;
}