码迷,mamicode.com
首页 > 其他好文 > 详细

SP8064 AMR10J-Mixing Chemicals

时间:2020-10-26 10:50:54      阅读:17      评论:0      收藏:0      [点我收藏+]

标签:颜色   节点   允许   amr   play   div   return   结果   状态   

SP8064 AMR10J - Mixing Chemicals

给一个\(n\)个节点的基环树森林,求\(k\)分图染色的方案数

先考虑一棵树的方案,随机选一个点为根,然后其它每个节点都有唯一一个前驱,根往叶子节点确定颜色,根有\(k\)种染色方案,其他节点只要与前驱不同即可,染,色方案有\(k-1\)种,乘法原理,假设这棵树的节点数为\(n\),这棵树\(k\)分图染色的方案数是\(k(k-1)^{n-1}\)

对于基环树来说,先确定环的颜色,再确定其它点的颜色,同样的,其他点只有唯一一个前驱,所以方案数还是\(k-1\),不妨设给一个大小为\(x\)的环进行\(k\)分图染色方案为\(f_x\),那么给定节点\(n\),环大小为\(x\)的基环树\(k\)分图染色的方案数就是\(f_x(k-1)^{n-x}\)
森林的方案可以乘起来,接下来就是如何求\(f_x\)

算法一:dp

暴力\(dp\)

\(g_{i,j,k}\)表示考虑完前\(i\)个节点放的颜色,第\(i\)个节点颜色为\(j\),第\(1\)个节点颜色为\(k\)的方案数,\(f_x=\sum\limits_{i\not=j}g_{x,i,j}\)

考虑减小状态数量,每种颜色 本质没有区别,我们不用关系颜色具体是什么,仅关系选出的颜色与第一个节点颜色是否相同,不妨设\(g_{i,0/1}\)考虑完前\(i\)个节点放的颜色,第\(i\)个节点的颜色是否与第一个节点颜色相同方案数,

\(0\)代表相同,\(1\)代表不同,\(f_x=g_{x,0}\) 朴素转移:

\[\large g_{x,0}=g_{x-1,1},g_{x,1}=g_{x-1,0}\times(k-1)+g_{x-1,1}\times(k-2) \]

第一个转移:\(x\)\(1\)相同,该点只有一种选择,同时\(x-1\)肯定和\(1\)不相同;

第二个转移:\(x\)\(1\)不同,\(x-1\)\(1\)相同时,\(x\)\(k-1\)种选择,\(x-1\)\(1\)不同时,该点只有\(k-2\)种选择

由这个柿子,我们可以看出,不妨用\(g_{x,0}\)代表\(g_{x-1,1}\),用\(f_x\)代表\(g_{x,0}\),转移也可以写成

\(\large f_{x+1}=f_{x-1}\times(k-1)+f_x\times(k-2)\)

\[\large f_x=f_{x-1}\times(k-2)+f_{x-2}\times(k-1) \]

一个标准的矩阵快速幂柿子,直接\(O(n)\)求和,复杂度\(O(\sum n)\)

算法二:数学

对于一个大小为\(n\)的环最终染色结果,如果允许相邻点颜色相同,我们就认为它们间的边被标记了

显然标记\(x(x\not=n)\)条边方案数为\(\large{n\choose x}f_{n-x}\),把同色点缩点即可证明,

标记边数量等于等于\(n\),方案数即为\(k\),(所有边颜色相同)

标记边数量可能为\(0,1,..,n-2,n\)(不能有\(n-1\),因为不可能只标记\(n-1\)条边),画图可知,

任意染色方案数为\(k^n\),所以可以得到以下柿子

\[k^n=\sum_{i=0}^{n-2}{n\choose i}f_{n-i}+k \]

\[k^n=\sum_{i=2}^n{n\choose i}f_i+k \]

手膜一下,把范围扔进柿子就好了,现在就可以\(O(n^2)\)\(f\)

二项式反演降低复杂度:

\[\large\sum_{i=0}^n{n\choose i}f_i=\begin{cases}1~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~n=0\k^n-k+kn+1~~~~n>0 \end{cases} \]

\(\large g_n=\sum\limits_{i=0}^n{n\choose i}f_i\),那么

\[\large f_n=\sum_{i=0}^n(-1)^{n-i}{n\choose i}g_i \]

const int mod = 1e9 + 7,N = 105;
inline void write(int x) {
  static int sta[64];
  int top = 0;
  do {
    sta[top++] = x % 10, x /= 10;
  } while (x);
  while (top) putchar(sta[--top] + 48); putchar(‘\n‘);
}    
int mo(const int x){return x >= mod ? x-mod : x;}
int g[N],tot,ok[N],st[N],vis[N],c[N];
int dfs(int u){
	if(vis[u]) return ok[u] ? -1 : vis[u];
	st[++tot] = u; vis[u] = tot;
	return dfs(c[u]);
}
int main(){
	int T = read();
	while(T--){
		int n,k; g[0] = 1; g[1] = 0;
		n = read(); k = read();
		for(int i = 2;i <= n;++i)
			g[i] = mo(1ll*g[i-1]*(k-2)%mod + 1ll*g[i-2]*(k-1)%mod);
		for(int i = 0;i <= n;++i)
			g[i] = 1ll*g[i]*k % mod;
		for(int i = 1;i <= n;++i)
			c[i] = read(),vis[i] = ok[i] = 0,++c[i];
		int sum = n,ans = 1;
		for(int i = 1;i <= n;++i){
			if(!vis[i]){
				tot = 0;int tmp = dfs(i);
				for(int j = 1;j <= tot;++j)
					ok[st[j]] = true;
				if(~tmp){
					tmp = tot - tmp + 1;sum -= tmp;
					ans = 1ll*ans*g[tmp] % mod;
				}
			}
		}
		int sna = 1;
		while(sum--)
			sna = 1ll*sna*(k-1) % mod;
		write(1ll*ans*sna%mod);
	}
}

SP8064 AMR10J-Mixing Chemicals

标签:颜色   节点   允许   amr   play   div   return   结果   状态   

原文地址:https://www.cnblogs.com/shikeyu/p/13870786.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!