zoukankan      html  css  js  c++  java
  • 【UOJ348】【WC2018】州区划分 状压DP FWT

    题目大意

      给定一个(n)个点的无向图,对于每种 (n) 个点的划分({S_1,S_2,ldots,S_k}),定义它是合法的,当且仅当每个点都在其中的一个集合中且对于任何的(iin[1,k]),点集(S_i)非空,且导出子图不存在欧拉回路。

      给定数组(w_i),求对于所有合法的划分({s_1,s_2,ldots,s_k}),下面的式子之和

    [{(prod_{i=1}^kfrac{sum_{xin S_i}w_x}{sum_{j=1}^isum_{xin S_j}w_x})}^p ]

      (nleq 21)

    题解

      先用(O(n^22^n))判断每个点集是否合法,并计算(g(S)={(sum_{xin S}w_x)}^p)。如果(S)不合法。那么(g(S)=0)

      很容易想到一个(O(3^n))的做法。

      设(f(S))为当前选择的集合为(S)的答案

    [f(S)=frac{sum_{Tsubseteq S}g(T) f(Ssetminus T)}{g(S)} ]

      可以发现这是一个子集卷积。

      一种可行的做法是把子集卷积转化为子集或卷积。

      定义(widetilde{f})(f)的集合占位幂级数,当且仅当对于所有的(S)满足(widetilde{f}(S))是一个(|S|)次多项式,且([x^{|S|}]widetilde{f}(S)=f(S))

      可以发现,若(p(S)=widetilde f(S)cdot widetilde g(S)),则(p)(f imes g)的占位多项式。

      所以我们可以在(O(n^22^n))内计算子集卷积了。

      回到这道题,我们假设每个城市可以出现在多个州里,记(h_{i,S})为每个州的城市个数之和为(i),每个州的城市的并集为(S)的方案数。那么(F(S)=sum_{i=1}^nh_{i,S}x^i)就是(f(S))的集合占位幂级数。

      所以(f(S)=h_{|S|,S}),状态转移方程是

    [h_{i,S}=sum_{j=1}^isum_{|T|=j}sum_{A}[A|T=S]h_{i-j,A}frac{g(T)}{g(S)} ]

      记(G(i)=sum_{|S|=i}g(S)x^S)

      我们先枚举(i),再枚举(j),然后计算(h_i=h_{i-j} imes G(j))

      这里我们可以全程用莫比乌斯变换后的值,卷积一次就是(O(2^n))

      还有,我们这里要除以(g(S)),可以在做完一层((h_i))之后变换回去,除以(g(S)),再变换回来。

      这样时间复杂度就是(O(n^22^n))的了。

    代码

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<ctime>
    #include<cstdlib>
    #include<utility>
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    void open(const char *s)
    {
    #ifndef ONLINE_JUDGE
        char str[100];
        sprintf(str,"%s.in",s);
        freopen(str,"r",stdin);
        sprintf(str,"%s.out",s);
        freopen(str,"w",stdout);
    #endif
    }
    const ll p=998244353;
    ll fp(ll a,ll b)
    {
    	ll s=1;
    	for(;b;b>>=1,a=a*a%p)
    		if(b&1)
    			s=s*a%p;
    	return s;
    }
    int lx[100010];
    int ly[100010];
    int n,m,o;
    void fwt(int *a)
    {
    	int i,j;
    	for(j=1;j<1<<n;j<<=1)
    		for(i=0;i<1<<n;i++)
    			if(i&j)
    				a[i]=(a[i]+a[i^j])%p;
    }
    void ifwt(int *a)
    {
    	int i,j;
    	for(j=1;j<1<<n;j<<=1)
    		for(i=0;i<1<<n;i++)
    			if(i&j)
    				a[i]=(a[i]-a[i^j])%p;
    }
    int f[22][1<<21];
    int g[22][1<<21];
    ll inv[100010];
    ll fw[1<<21];
    ll fwi[1<<21];
    int w[30];
    int fa[100010];
    int num[1<<21];
    int find(int x)
    {
    	return fa[x]==x?x:fa[x]=find(fa[x]);
    }
    int c[1<<21];
    int d[100010];
    int main()
    {
    	open("walk");
    	int i,j,k;
    	inv[0]=inv[1]=1;
    	for(i=2;i<=10000;i++)
    		inv[i]=-p/i*inv[p%i]%p;
    	scanf("%d%d%d",&n,&m,&o);
    	for(i=1;i<=m;i++)
    		scanf("%d%d",&lx[i],&ly[i]);
    	for(i=1;i<=n;i++)
    		scanf("%d",&w[i]);
    	int all=(1<<n)-1;
    	for(i=1;i<=all;i++)
    	{
    		for(j=1;j<=n;j++)
    		{
    			d[j]=0;
    			fa[j]=j;
    		}
    		for(j=1;j<=m;j++)
    			if(((i>>(lx[j]-1))&1)&&((i>>(ly[j]-1))&1))
    			{
    				d[lx[j]]^=1;
    				d[ly[j]]^=1;
    				int fx=find(lx[j]);
    				int fy=find(ly[j]);
    				if(fx!=fy)
    					fa[fx]=fy;
    			}
    		fw[i]=0;
    		for(j=1;j<=n;j++)
    			if((i>>(j-1))&1)
    				fw[i]+=w[j];
    		fwi[i]=inv[fw[i]];
    		fw[i]=fp(fw[i],o);
    		fwi[i]=fp(fwi[i],o);
    		int cnt=0;
    		c[i]=0;
    		for(j=1;j<=n;j++)
    			if((i>>(j-1))&1)
    			{
    				num[i]++;
    				if(fa[j]==j)
    				{
    					cnt++;
    					if(cnt>=2)
    						c[i]=1;
    				}
    				if(d[j])
    					c[i]=1;
    			}
    		fw[i]*=c[i];
    		g[num[i]][i]=fw[i];
    	}
    	f[0][0]=1;
    	for(i=1;i<=n;i++)
    		fwt(g[i]);
    	fwt(f[0]);
    	for(i=1;i<=n;i++)
    	{
    		for(j=1;j<=i;j++)
    			for(k=0;k<=all;k++)
    				f[i][k]=(f[i][k]+(ll)f[i-j][k]*g[j][k])%p;
    		ifwt(f[i]);
    		for(j=0;j<=all;j++)
    			f[i][j]=f[i][j]*fwi[j]%p;
    		fwt(f[i]);
    	}
    	ifwt(f[n]);
    	ll ans=f[n][all];
    	ans=(ans+p)%p;
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    qt中qmake的详解
    教程:从零开始 使用Python进行深度学习!
    win10系统下搭建Python开发环境和TensorFlow深度学习环境(CPU版)
    怎么选择视觉光源颜色
    pycharm安装及设置中文
    新建DataSet和DataTable,并从中提取数据到文本
    网站服务基础面试
    TCP、UDP数据包大小的限制
    TCP的三次握手与四次挥手理解及面试题(很全面)
    zabbix服务深入
  • 原文地址:https://www.cnblogs.com/ywwyww/p/8514554.html
Copyright © 2011-2022 走看看