链接:https://ac.nowcoder.com/acm/problem/13884
来源:牛客网
题目描述
We have n empty boxes, so let’s recolor those boxes with m colors.
The boxes are put in a line. It is not allowed to color any adjacent boxes with the same color. Boxes i and i+1 are said to be adjacent for every i,1≤i≤n.
And we also want the total number of different colors of the n boxes being exactly k.
Two ways are considered different if and only if there is at least one box being colored with different colors.
输入描述:
The first line of the input contains integer T(1≤T≤100) -the number of the test cases
For each case: there will be one line, which contains three integers n,m,k(1≤n,m≤109 1≤k≤106, k≤n,m).
输出描述:
For each test case, you need print an integer means the number of ways of different coloring methods modulo 109+7.
示例1
输入
复制2 3 2 2 3 2 1
2 3 2 2 3 2 1
输出
复制2 0
2 0
说明
In the first example we have two ways: 121 212 where 1 and 2 are two different color. In the second example we can't do that.
思路:
首先从m中颜色中选k个来作为涂色的当前颜色方案,然后用i个颜色为box涂色的方案为:f(i)=i*(i-1)^(n-1),即:第一次可从i种颜色中选一个来涂,但是因为相邻的box颜色不能相同,所以,后面n-1个box都是从除去前一种的i-1中中选一个来涂色。
这题的关键在于恰好k种颜色所以利用容斥原理来求:
即:最终方案数=至多用k种颜色方案数-至多用k-1种颜色方案数+至多用k-2种颜色方案数-至多用k-3种颜色方案数+...+(-)至多用1种颜色方案数。
最后,利用乘法原理将选出k种颜色的方法数与用k种颜色上色的方法数相乘,得到的答案就是:
C(m,k)* (C(k,k)* f(k)-C(k,k-1)* f(k-1)+C(k,k-2)* f(k-2)-...+(-1)^{k}(−1)k* f(1))
其中因为m较大,所以不能预处理出阶乘和阶乘的逆元,而k较小,且C(m,k)只需求一次,所以可直接计算得到其结果;而C(k,i)则可以由C(k,i-1)推出:
即C(k,i) = k*(k-1)*(k-i+1)/i! = (k/1)*((k-1)/2)*..*(k-i+1/i)
而从后往前求可表示为:i/(k-i+1)*(i-1)/(k-i+1)*..*1/(k-i+1) i从k到1,
除以(k-i+1)可以转化为乘(k-i+1)的逆元: 即qpow((k-i+1),mod-2)
依次可以求出C(k,1) = i/(k-i+1) ,C(k,2) = i/(k-i+1)*((i-1)/(k-i+1) (即:C(k,2) = C(k,1)*(i-1)/(k-i+1) ) .....
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long
using namespace std;
const int mod=1e9+7;
int t,n,m,k;
int qpow(int a,int b)
{
int res=1%mod;
while(b){
if(b&1) res=res*a%mod;
a=a*a%mod;
b>>=1;
}
return res;
}
int C(int n,int m)
{
if(n<m) return 0;
if(n-m<m) m=n-m;
int a=1,b=1;
for(int i=0;i<m;i++){
a=(a*(n-i))%mod,b=(b*(i+1))%mod;
}
return a*qpow(b,mod-2)%mod;
}
signed main()
{
cin>>t;
while(t--){
cin>>n>>m>>k;
int sum=0,c=1;
for(int i=k;i>=1;i--){
sum=(sum+i*qpow(i-1,n-1)%mod*c%mod+mod)%mod;
c=-1*c*i%mod*qpow(k-i+1,mod-2)%mod;
}
int res=sum*C(m,k)%mod;
cout<<res<<endl;
}
return 0;
}