[BZOJ 2560]串珠子

传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=2560

Sol

正难则反 直接统计可行的状态不好统计 就反过来统计不可行的状态 再用所有状态减去不可行的状态

在算不可行状态的时候 固定一个定点 与这个定点联通的点为集合$st1$ 与这个定点不连通的点为集合$st2$

引入$f,g$ $g$表示随意连边可产生的方案数 $f$为连边联通的方案数

这样产生的不合法方案数$g_{st2}*f_{st1}$

而由于固定了一个定点 所以可以保证算出来的方案数不重不漏

题目同时涉及了一个枚举子集的方法=v=

 

Code

 

#include <bits/stdc++.h> 
using namespace std;
const int fish=1000000007;
int N;
long long a[1000][1000],f[65550],g[65550];
int main()
{
    scanf("%d",&N);
    for (int i=1;i<=N;i++)
      for (int j=1;j<=N;j++)
        scanf("%d",&a[i][j]);
    int ST=(1<<N)-1;
    for (int i=1;i<=ST;i++)
      {
          g[i]=1;
          for (int j=1;j<=N;j++)
            if (i&(1<<(j-1)))
              for (int k=j+1;k<=N;k++)
                if (i&(1<<k-1))
                  g[i]=g[i]*(a[j][k]+1)%fish;
          f[i]=g[i];
          int zt=0;
          for (int j=N;j>=0;j--)
               if (i&(1<<j-1))
               {
                   zt=j;
                   break;
            }
        zt=i^(1<<zt-1);
        for (int j=zt;j;j=zt&(j-1))//枚举所有子集的方法 
          f[i]=(f[i]-g[j]*f[i^j]*1ll%fish+fish)%fish;
      }
    printf("%lld",f[ST]%fish);
    return 0;
}

 

posted @ 2019-08-17 15:16  si_nian  阅读(268)  评论(0编辑  收藏  举报