牛客挑战赛48C.铬合金之声
思路:
首先由题很显然的一个结论就是,这是由
n
n
n个点构成的有
n
−
m
n-m
n−m棵无根树的森林。
考虑权值的计算。假设第
i
i
i棵树的大小为
s
i
s_i
si,权值就为
∏
i
=
1
n
−
m
s
i
\prod\limits_{i=1}^{n-m}s_i
i=1∏n−msi。但是这样的话,又要考虑乘上方案数,并且每种方案都需要分开考虑。很巧妙的一步就是,将无根树转换为有根树,因为有根树的方案数就等于无根树的方案数乘上结点数,恰好是我们需要的贡献。
所以转换成了求
n
n
n个点构成
n
−
m
n-m
n−m棵有根树的方案数。
这一步也很巧妙。我们设一个虚根
0
0
0,令其度数为
n
−
m
n-m
n−m。通过Prufer序列的定义,我们可以发现
0
0
0会在长度为
n
−
1
n-1
n−1的序列种出现
n
−
m
−
1
n-m-1
n−m−1次,所以它的方案数为
(
n
−
1
n
−
m
−
1
)
=
(
n
−
1
m
)
\begin{pmatrix}n-1\\n-m-1\end{pmatrix}=\begin{pmatrix}n-1\\m\end{pmatrix}
(n−1n−m−1)=(n−1m)。剩下的
m
m
m个位置中,每个位置都可以从
1
,
2
,
⋯
,
n
1,2,\cdots,n
1,2,⋯,n中任选一个数,所以方案数为
n
m
n^m
nm。通过乘法原理,总的方案数为
(
n
−
1
m
)
n
m
\begin{pmatrix}n-1\\m\end{pmatrix}n^m
(n−1m)nm。
(
n
−
1
m
)
=
(
n
−
1
)
!
m
!
(
n
−
1
−
m
)
!
\begin{pmatrix}n-1\\m\end{pmatrix}=\cfrac{(n-1)!}{m!(n-1-m)!}
(n−1m)=m!(n−1−m)!(n−1)!,但是
n
n
n比较大,线性计算会T。所以稍微转换一下
(
n
−
1
m
)
=
(
n
−
1
)
m
‾
m
!
\begin{pmatrix}n-1\\m\end{pmatrix}=\cfrac{(n-1)^{\underline{m}}}{m!}
(n−1m)=m!(n−1)m。
公式的说明:
x
n
‾
=
{
1
n
=
0
x
(
x
−
1
)
n
−
1
‾
n
≥
1
x^{\underline{n}}=\begin{cases}1&n = 0 \\x(x-1)^{\underline{n-1} }&n\ge1\end{cases}
xn={1x(x−1)n−1n=0n≥1
这样就可以在
O
(
m
)
O(m)
O(m)的时间内求出答案了。
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define int long long
#define cl(x,y) memset(x,y,sizeof(x))
#define loop(x,y,z) for(x=y;x<=z;x++)
#define reve(x,y,z) for(x=y;x>=z;x--)
#define ct cerr<<"Time elapsed:"<<1.0*clock()/CLOCKS_PER_SEC<<"s.\n";
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define all(x) x.begin(),x.end()
#define lson x<<1,l,mid
#define rson x<<1|1,mid+1,r
#define INF 1e18
const int N=1e6+10;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
const double eps=1e-8;
const double pi=acos(-1);
using namespace std;
int qpow(int a,int b)
{
a%=mod;
int ans=1;
while(b)
{
if(b&1)
ans=ans*a%mod;
a=a*a%mod;
b>>=1;
}
return ans;
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,m,i;
cin>>n>>m;
int ans=1,tot=1;
for(i=1;i<=m;i++)
{
ans=ans*(n-i)%mod;
tot=tot*(m-i+1)%mod;
}
ans=ans*qpow(tot,mod-2)%mod*qpow(n,m)%mod;
cout<<ans<<endl;
return 0;
}