BZOJ 3812 主旋律

版权声明:本文为博主原创文章,未经博主允许可以转载,但要注明出处 https://blog.csdn.net/wang3312362136/article/details/85319696

题目链接

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

题解

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

假设 f s f_s 表示用 s s 这些点能构成的强连通图的个数, g s g_s 表示用 s s 这些点能构成的非强连通图的方案数,其中构成 i i 个强连通分量则对 g s g_s 的贡献为 ( 1 ) i (-1)^i 。容易发现
g s = f s t s , u t g t f s t g_s=f_s-\sum_{t\subset s,u\in t} g_tf_{s-t}
那么
f s = 2 e s t s , t ̸ = 2 e s t + e s t , t g s f_s=2^{e_s}-\sum_{t\subseteq s,t\not= \varnothing}2^{e_{s-t}+e_{s-t,t}}g_s
容易发现, f s f_s 此时需要的是不包含 f s f_s g s g_s ,因此 g s g_s 在求出 f s f_s 之前是不能 + f s +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;
}

猜你喜欢

转载自blog.csdn.net/wang3312362136/article/details/85319696