bzoj2560串珠子

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=2560

和地震后的幻想乡思路一样,枚举点集。

因为求不连通容易,所以容斥一下,用全集减去不连通的。

也还是为了不重不漏枚举一个划分点。

哎呀真是一模一样呢!

1.理解更深的一点:划分点的必要性。

  比如点集{1,2,3,4},如果不枚举划分点,减掉的东西里:1)当 f [ 1,2 ] 和 g [ 3,4 ] 的时候,含一个 f 1,2 ] x f [ 3,4 ],

                             2)当 f [ 3,4 ] 和 g [ 1,2 ] 的时候,含一个 f [ 1,2 ] x f [ 3,4 ];

    所以必须枚举划分点。

2.深刻的不明白的问题!

  发现如果指定连通的子集中必须包含划分点,就没问题;可是如果指定成连通的子集中必须不包含划分点,就错误。这是为什么?

    这都是因为那种  只有自己一个点还算联通  的情况太特殊了!

    考虑反例:其实就是会把那种图中一条边都没有的情况减好多遍。这种感觉。

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
const int N=16;const ll mod=1e9+7;
int n,c[N+5][N+5],lm;
ll f[(1<<N)+5],g[(1<<N)+5];
int main()
{
    scanf("%d",&n);lm=(1<<n);
    for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)scanf("%d",&c[i][j]);
    for(int s=1;s<lm;s++)
    {
        g[s]=1;
        for(int i=1;i<=n;i++)if(s&(1<<(i-1)))
            for(int j=i+1;j<=n;j++)if(s&(1<<(j-1)))
                (g[s]*=c[i][j]+1)%=mod;
        f[s]=g[s];
        int k;
        for(k=1;k<=n&&(s&(1<<(k-1)))==0;k++);
//        for(int j=((s-1)&s);j;j=((j-1)&s))if(j&(1<<(k-1)))    //50
//            (f[s]-=f[j]*g[s^j])%=mod;
        k=(s^(1<<(k-1)));    //50
        for(int j=k;j;j=((j-1)&k))f[s]=((f[s]-g[j]*f[s^j])%mod+mod)%mod;//不是&s! 
//        for(int j=((s-1)&s);j;j=((j-1)&s))if((j&(1<<(k-1)))==0)//49
//            (f[s]-=f[j]*g[s^j])%=mod;
    }
    printf("%lld",f[lm-1]);
    return 0;
}
原文地址:https://www.cnblogs.com/Narh/p/9136604.html