zoukankan      html  css  js  c++  java
  • bzoj4671. 异或图(斯特林反演)

    题目描述

    题解

    迫真例题

    (g[i])表示至少i个连通块的方案,(f[i])表示恰好i个连通块的方案(注意“至少”的含义)

    则有(g[i]=sum_{j>=i}S(j,i)f[i])

    斯特林反演:https://www.cnblogs.com/jz-597/p/13210825.html

    类似子集反演,有(f[i]=sum_{j>=i}(-1)^{j-i}s(j,i)g[i])

    考虑求g,枚举集合划分,不同集合里的点之间不能有边

    把有边的图丢到线性基S里,答案是(2^{s-|S|}-1)

    因为线性基里面的子集都不能选,全集挖掉线性基后的任意非空子集都可以选,选完后通过线性基里面的元素可以唯一使其合法

    注意线性基只用考虑两端在不同集合的边

    时间复杂度大概是(O(B_n*s*n^2))

    code

    #include <bits/stdc++.h>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define ll long long
    //#define file
    using namespace std;
    
    int a[11][11],d[11],N,n,m,i,j,k,l;
    ll p[61],f[61],b[61],g[11],ans;
    char st[51];
    bool Bz[51];
    
    void add(ll t)
    {
    	int i,j,k,l;
    	
    	fd(i,m,1)
    	if (t&p[i-1] && Bz[i])
    	{
    		if (!b[i]) {b[i]=t,--ans;break;}
    		t^=b[i];
    	}
    }
    
    void dg(int t,int tot)
    {
    	int i,j,k,l;
    	bool bz;
    	
    	if (t>n)
    	{
    		memset(b,0,sizeof(b)),ans=N;
    		fo(i,1,n-1) fo(j,i+1,n) Bz[a[i][j]]=d[i]!=d[j];
    		fo(i,1,N)
    		{
    			bz=0;
    			fo(j,1,n-1)
    			{
    				fo(k,j+1,n)
    				if (d[j]!=d[k] && (f[i]&p[a[j][k]-1]))
    				{add(f[i]);bz=1;break;}
    				if (bz) break;
    			}
    		}
    		
    		if (tot==2)
    		n=n;
    		
    		g[tot]+=p[ans]-1;
    		return;
    	}
    	
    	fo(i,1,tot) d[t]=i,dg(t+1,tot);
    	d[t]=tot+1,dg(t+1,tot+1);
    }
    
    int main()
    {
    	#ifdef file
    	freopen("bzoj4671.in","r",stdin);
    	#endif
    	
    	p[0]=1;
    	fo(i,1,60) p[i]=p[i-1]*2;
    	
    	scanf("%d",&N);
    	fo(k,1,N)
    	{
    		scanf("%s",st+1);l=strlen(st+1);
    		fo(i,1,l) f[k]+=p[i-1]*(st[i]=='1');
    		
    		if (!n)
    		{
    			while (n*(n-1)/2!=l) ++n;
    			l=0;
    			fo(i,1,n-1) fo(j,i+1,n) a[i][j]=++l;
    		}
    	}
    	
    	m=n*(n-1)/2;
    	dg(1,0);
    	
    	ans=0;
    	k=1;
    	fo(j,1,n)
    	{
    		if (j>1) k*=j-1;
    		ans+=(((j-1)&1)?-1:1)*g[j]*k;
    	}
    	printf("%lld
    ",ans);
    	
    	fclose(stdin);
    	fclose(stdout);
    	return 0;
    }
    
  • 相关阅读:
    java中的String.format使用
    白话解析平安笔试题:多线程交替打印
    centos7 yum install redis
    CentOS7 linux下yum安装redis以及使用
    开源规则流引擎实践
    java中System.err.print和System.out.print区别
    drools -规则语法
    小明历险记:规则引擎drools教程一
    规则引擎drools封装
    C#中Encoding.Unicode与Encoding.UTF8的区别
  • 原文地址:https://www.cnblogs.com/gmh77/p/13299741.html
Copyright © 2011-2022 走看看