题目描述
shy有一颗树,树有n个结点。有k种不同颜色的染料给树染色。一个染色方案是合法的,当且仅当对于所有相同颜色的点对(x,y),x到y的路径上的所有点的颜色都要与x和y相同。请统计方案数
题解
太妙了太妙了,
1.首先既然任意相同颜色的点的路径均为一个颜色,那这其实就是当于一个联通块。
那么本题就转化为把这颗树划分为小于等于k的连通块,然后在这些颜色相同的连通块上任意染色就可以了。
2.所以我们可以枚举连通块的个数,然后用这棵树能划分成这些连通块的方案数*染色的排列组合就能得到答案
3.那现在的问题就是怎么求i个连通块的方案数?
由于这是一颗树,任意一条边都连接着两个连通块,那么将这颗树划分为i个连通块,其实就是相当于在这n-1条中选择i-1条边删掉,所以方案数就为C(n-1,i-1);
代码
#include<bits/stdc++.h> #define ls rt<<1 #define rs rt<<1|1 #define pb push_back #define fi first #define se second #define ios ios::sync_with_stdio(0); using namespace std; typedef long long LL; typedef pair<int, int> PII; typedef vector<int> VI; const int maxn = 2e6 + 6; const LL inf = 0x3f3f3f3f3f3f3f3f; const int mod = 1e9+7; LL qp(LL x,LL y){LL ans=1;x%=mod;while(y){if(y&1) ans=ans*x%mod;x=x*x%mod;y>>=1;}return ans;} LL inv(LL x){return qp(x,mod-2);} //head int n,k; LL f[maxn]; LL C(int n,int m){ if(m>n) return 0; return f[n]*inv(f[n-m])%mod*inv(f[m])%mod; } LL calu(int i){ return C(n-1,i-1)*f[k]%mod*inv(f[k-i])%mod; } int main(){ scanf("%d%d",&n,&k); f[0]=1; for(int i=1;i<=10000;i++){ f[i]=f[i-1]*i%mod; } LL ans=0; for(int i=1;i<=k;i++){ (ans+=calu(i))%=mod; } printf("%lld\n",ans); }