【JZOJ 6079】【GDOI2019模拟2019.3.23】染色问题

Description

在这里插入图片描述
m ≤ n + 5 , k , n ≤ 1 0 5 m\leq n+5,k,n\leq10^5 mn+5k,n105

Solution 1

这个图只有5条返祖边所以才能做,

先把所有有返祖边的点拿出来,(姑且叫做返祖点)
自然地,考虑容斥,枚举一条返祖边的两个点是否同色,以及返祖边点之间的染色情况,
枚举后DP计算,设 f x , i f_{x,i} fx,i表示点x染颜色i时的方案数,注意颜色0表示其他颜色,即没有被枚举的颜色,

因为有6条返祖边,所以染色情况最多877种(贝尔数),每次DP至少需要O(n)时间,过不了考虑优化,

显然的,所有度数为1的点都可以删掉,他们对ans的贡献恒为(K-1),
删完以后再把链缩一下就是返祖点构成的虚树了,

缩链简单,像矩阵乘法那样弄就好了,

这样每次DP的复杂度就很小了,直接在虚树上跑即可,

复杂度: O ( k 3 n + 2 B k k ) O(k^3n+2B_kk) O(k3n+2Bkk)
(前面的预处理+后面的枚举及DP)

Solution 2

先转化一下,
原图的每条边都有两个值(a,b),分别表示如果两个点同色的贡献和不同色的贡献,
对于一种染色方案,答案为所有边的贡献乘起来,
显然的,对于原图,每条边的值为(0,1),

考虑缩点,
显然的叶子可以直接缩点,他们对ans的贡献恒为(K-1),

对于度数为2的点,可以通过以下方式缩掉:
设点 u u u数为2,它连向的两个点为 v 1 , v 2 v_1,v_2 v1,v2,边 ( u , v 1 ) (u,v_1) (u,v1)的值为 ( a 1 , b 1 ) (a_1,b_1) (a1,b1),边 ( u , v 2 ) (u,v_2) (u,v2)的值为 ( a 2 , b 2 ) (a_2,b_2) (a2,b2)
删去点 u u u以及其连出去的边,
添加边 ( v 1 , v 2 ) (v_1,v_2) (v1,v2),其值为 ( a 1 a 2 + b 1 b 2 ( K − 1 ) , a 1 b 2 + b 1 a 2 + b 1 b 2 ( K − 2 ) ) (a_1a_2+b_1b_2(K-1),a_1b_2+b_1a_2+b_1b_2(K-2)) (a1a2+b1b2(K1),a1b2+b1a2+b1b2(K2))

这样不停的缩点,最后最多只会剩下10个点15条边,
这么小暴力即可,跑个状压DP子集转移之类的即可

Code

#include 
#include 
#include 
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define efo(i,q) for(int i=A[q];i;i=B[i][0])
#define min(q,w) ((q)>(w)?(w):(q))
#define max(q,w) ((q)<(w)?(w):(q))
using namespace std;
typedef long long LL;
const int N=100500,mo=1e9+7;
int read(int &n)
{
	char ch=' ';int q=0,w=1;
	for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
	if(ch=='-')w=-1,ch=getchar();
	for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int m,n,K,root;
LL ans;
int B[2*N][3],A[N],B0=1,Bv[N];
int Fa[N],Fav[N],Jp[N],d[N];
int HU[10][2],HU0;
int z[N];
int g[7][N][7][7],gmx;
LL f[N][9];
LL jc[N],jcn[N];
int MOJ(LL &q,int w){return (q+=w)>=mo?q-=mo:q;}
int MOJ(int &q,int w){return (q+=w)>=mo?q-=mo:q;}
LL ksm(LL q,int w)
{
	LL ans=1;
	for(;w;w>>=1,q=q*q%mo)if(w&1)ans=ans*q%mo;
	return ans;
}
LL P(int m,int n){return jc[m]*jcn[m-n]%mo;}
void link(int q,int w)
{
	++Bv[q],++Bv[w];
	B[++B0][0]=A[q],A[q]=B0,B[B0][1]=w;
	B[++B0][0]=A[w],A[w]=B0,B[B0][1]=q;
}
void dfsh(int q,int fa)
{
	z[q]=1;
	efo(i,q)if(!B[i][2]&&B[i][1]!=fa)
	{
		if(!z[B[i][1]])dfsh(B[i][1],q);
		else B[i][2]=B[i^1][2]=1,HU[++HU0][0]=q,HU[HU0][1]=B[i][1];
	}
}
int dfsf(int q,int fa,int c)
{
	Fav[q]=max(0,c-1);gmx=max(gmx,Fav[q]);
	Jp[q]=q;Fa[q]=fa;
	f[q][0]=1;
	if(B[B[A[q]][0]][0])c=0;
	efo(i,q)if(!B[i][2]&&B[i][1]!=fa)
	{
		Jp[q]=dfsf(B[i][1],q,c+1);
		f[q][0]=f[q][0]*f[B[i][1]][0]%mo*(K-1LL)%mo;
	}
	return (B[B[A[q]][0]][0]||!fa)?(Jp[q]=q):Jp[q];
}
void dfs(int q,int fa,int cnt)
{
	int Q=q;q=Jp[q];
	fo(i,0,cnt)f[q][i]=1;
	efo(i,q)if(!B[i][2]&&B[i][1]!=Fa[q])
	{
		dfs(B[i][1],q,cnt);
		LL t=f[B[i][1]][0]*(K-cnt-1)%mo;
		fo(j,1,cnt)MOJ(t,f[B[i][1]][j]);
		f[q][0]=f[q][0]*(t)%mo;
		MOJ(t,f[B[i][1]][0]);
		fo(j,1,cnt)f[q][j]=f[q][j]*(t-f[B[i][1]][j])%mo;
	}
	if(z[q])
	{
		if(z[q]<=cnt)
		{
			fo(i,0,cnt)if(i!=z[q])f[q][i]=0;
		}
		else fo(i,1,cnt)f[q][i]=0;
	}
	if(Fav[q])
	{
		fo(i,0,cnt)
			fo(j,0,cnt)f[0][i]=(f[0][i]+f[q][j]*g[cnt][Fav[q]][i][j])%mo;
		fo(i,0,cnt)f[Q][i]=f[0][i],f[0][i]=0;
	}
}
void ss(int q,int w,int e)
{
	if(q>HU0)
	{
		if(!w)return;
		w=min(w,K-1);
		dfs(root,0,w);
		f[root][0]=f[root][0]*(K-w)%mo;
		fo(j,1,w)MOJ(f[root][0],f[root][j]);
		f[root][0]=f[root][0]*P(K,w)%mo;
		if(e&1)ans=(ans-f[root][0])%mo;
		else ans=(ans+f[root][0])%mo;
		return;
	}
	ss(q+1,w,e);
	++e;
	if(z[HU[q][0]]&&!z[HU[q][1]])
	{
		z[HU[q][1]]=z[HU[q][0]];ss(q+1,w,e);
		z[HU[q][1]]=0;return;
	}
	if(z[HU[q][1]]&&!z[HU[q][0]])
	{
		z[HU[q][0]]=z[HU[q][1]];ss(q+1,w,e);
		z[HU[q][0]]=0;return;
	}
	if(z[HU[q][0]]&&z[HU[q][1]])
	{
		if(z[HU[q][0]]==z[HU[q][1]])ss(q+1,w,e);
		return;
	}
	if(w<K)z[HU[q][0]]=z[HU[q][1]]=w+1,ss(q+1,w+1,e);
	fo(i,1,w)z[HU[q][0]]=z[HU[q][1]]=i,ss(q+1,w,e);
	z[HU[q][0]]=z[HU[q][1]]=0;
}
int main()
{
	freopen("color.in","r",stdin);
	freopen("color.out","w",stdout);
	int q,w;
	read(n),read(m),read(K);
	if(n==m+1)return printf("%lld\n",K*ksm(K-1,n-1)%mo),0;
	jc[0]=1;fo(i,1,K)jc[i]=jc[i-1]*i%mo;
	jcn[K]=ksm(jc[K],mo-2);fod(i,K-1,0)jcn[i]=jcn[i+1]*(i+1LL)%mo;
	fo(i,1,m)read(q),read(w),link(q,w);
	dfsh(1,0);
	fo(i,1,n)if(Bv[i]==1)d[++d[0]]=i;
	LL Ansc=1;
	for(;d[0];)
	{
		q=d[d[0]];--d[0];
		z[q]=0;Ansc=Ansc*(K-1LL)%mo;
		efo(i,q)if((--Bv[B[i][1]])==1)d[++d[0]]=B[i][1];
	}
	fo(I,1,n)if(z[I])
	{
		for(int i=A[I],i1=0;i;i=B[i][0])if(!z[B[i][1]])
		{
			if(i1)B[i1][0]=B[i][0];
			else A[I]=B[i][0];
		}else i1=i;
	}
	fo(i,1,n)if(z[i]){root=i;break;}
	fo(i,0,n)z[i]=0;
	dfsf(root,0,0);
	ans=f[root][0]*K%mo;
	fo(I,1,min(K-1,HU0))
	{
		fo(i,0,I)g[I][0][i][i]=1;
		fo(i,1,gmx)
		{
			fo(k,0,I)g[I][i][0][k]=(LL)g[I][i-1][0][k]*(K-I-1LL)%mo;
			fo(j,1,I)fo(k,0,I)MOJ(g[I][i][0][k],g[I][i-1][j][k]);
			fo(j,1,I)fo(k,0,I)g[I][i][j][k]=((LL)g[I][i][0][k]+g[I][i-1][0][k]-g[I][i-1][j][k])%mo;
		}
	}
	ss(1,0,0);
	ans=ans*Ansc%mo;
	printf("%lld\n",(ans+mo)%mo);
	return 0;
}

你可能感兴趣的:(妙啊)