【JZOJ 6079】【GDOI2019模擬2019.3.23】染色問題

Description

在這裏插入圖片描述
mn+5k,n105m\leq n+5,k,n\leq10^5

Solution 1

這個圖只有5條返祖邊所以才能做,

先把所有有返祖邊的點拿出來,(姑且叫做返祖點)
自然地,考慮容斥,枚舉一條返祖邊的兩個點是否同色,以及返祖邊點之間的染色情況,
枚舉後DP計算,設fx,if_{x,i}表示點x染顏色i時的方案數,注意顏色0表示其他顏色,即沒有被枚舉的顏色,

因爲有6條返祖邊,所以染色情況最多877種(貝爾數),每次DP至少需要O(n)時間,過不了考慮優化,

顯然的,所有度數爲1的點都可以刪掉,他們對ans的貢獻恆爲(K-1),
刪完以後再把鏈縮一下就是返祖點構成的虛樹了,

縮鏈簡單,像矩陣乘法那樣弄就好了,

這樣每次DP的複雜度就很小了,直接在虛樹上跑即可,

複雜度:O(k3n+2Bkk)O(k^3n+2B_kk)
(前面的預處理+後面的枚舉及DP)

Solution 2

先轉化一下,
原圖的每條邊都有兩個值(a,b),分別表示如果兩個點同色的貢獻和不同色的貢獻,
對於一種染色方案,答案爲所有邊的貢獻乘起來,
顯然的,對於原圖,每條邊的值爲(0,1),

考慮縮點,
顯然的葉子可以直接縮點,他們對ans的貢獻恆爲(K-1),

對於度數爲2的點,可以通過以下方式縮掉:
設點uu數爲2,它連向的兩個點爲v1,v2v_1,v_2,邊(u,v1)(u,v_1)的值爲(a1,b1)(a_1,b_1),邊(u,v2)(u,v_2)的值爲(a2,b2)(a_2,b_2)
刪去點uu以及其連出去的邊,
添加邊(v1,v2)(v_1,v_2),其值爲(a1a2+b1b2(K1),a1b2+b1a2+b1b2(K2))(a_1a_2+b_1b_2(K-1),a_1b_2+b_1a_2+b_1b_2(K-2))

這樣不停的縮點,最後最多隻會剩下10個點15條邊,
這麼小暴力即可,跑個狀壓DP子集轉移之類的即可

Code

#include <cstdio>
#include <algorithm>
#include <iostream>
#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章