您的位置:首页 > 其它

HDU 5622 KK's Chemical DP

2016-02-09 13:46 141 查看
题意:bc round 71(中文题面)

分析(官方题解):

根据药品之间的相互关系,我们可以构建一张图,我们对相互会发生反应的药品连边

这个图的特征,是一个环加上一些“树”(可能有多个联通块)

一个环(1,2,3,4,5……,n)m染色的方案数:递推,设第一个点颜色为1

f[I,1]表示i点颜色为1的种数,f[I,0]为颜色不为1时(不考虑n与1颜色不同)

则F[I,0]=f[i-1,0]*(m-2)+f[i-1,1]*(m-1),F[I,1]=f[i-1,0]

那么方案数为f[n,0]*m

一个根节点颜色固定且有k个孩子的树的m染色的方案数=(m-1)^k

​​ ,因为每个点的颜色只要与他的父亲颜色不同,即m-1种

因为乘法原理,一个联通块的方案数=环方案数*以环上每个点为根的树的积。多个联通块,再连乘即可

注:其实就是n个点的无向图k染色,相邻的节点颜色不一样,但是这个无向图有一个特点

就是其实无向图是由有向图(把方向去掉)变过来的,每个点的出度为1,所以不存在两个环(如果存在,至少存在一个点出度为2)

也就是官方题解说的,每一个连通块是由一个环和若干树组成

附上代码,这样的话时间复杂度是O(n)

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
using namespace std;
typedef long long LL;
const int N=1e2+5;
const LL mod=1e9+7;
LL dp
[2],k;
int c
,n,T,vis
;
void init()
{
dp[1][0]=0,dp[1][1]=1;
for(int i=2; i<=n; ++i)
{
dp[i][0]=(dp[i-1][0]*(k-2)%mod+dp[i-1][1]*(k-1)%mod)%mod;
dp[i][1]=dp[i-1][0];
}
memset(vis,-1,sizeof(vis));
}
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%I64d",&n,&k);
init();
for(int i=0; i<n; ++i)
scanf("%d",&c[i]);
int cnt=0;
LL ans=1;
for(int i=0; i<n; ++i)
{
if(vis[i]!=-1)continue;
int x=i;
while(vis[x]==-1)
{
vis[x]=i;
x=c[x];
}
if(vis[x]!=i)continue;
int tmp=0,u=x;
do
{
++tmp;
x=c[x];
}while(x!=u);
ans=ans*(dp[tmp][0]*k%mod)%mod;
cnt+=tmp;
}
cnt=n-cnt;
for(int i=0;i<cnt;++i)
ans=ans*(k-1)%mod;
printf("%I64d\n",ans);
}
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: