考虑任意一个节点
v
:
(1)若
则此时
(2)若
v
射出的边与某点射出的边形成重边,则当只有1个节点与其连边(就是那个与其产生重边的点)时,
则此时
v
不为割点的方案数为
(3)若
v
射出一条不为重边的边,且没有其他节点射入
(4)若
v
射出一条不为重边的边,且超过1个节点射入
(5)此时只需要计算
最后用
nn
减去上述所有的方案数即可得到
v
成为割点的次数,乘
注意要为阶乘的逆元打表,不然上述做法会t。
代码里的公式有些混乱,还是看上面的分析吧。
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define clr(a) memset(a,0,sizeof(a))
typedef long long ll;
const ll md=1000000007;
ll fr[100010],qn[100010];int ct=0;
ll qni(ll a,ll n){
ll r=1;for(;n;n>>=1,a=a*a%md)if(n&1)
r=r*a%md;
return r;
};
void _init(){
int i;for(fr[0]=1,i=1;i<=100000;++i)
fr[i]=(fr[i-1]*i)%md;
for(i=0;i<=100000;++i)qn[i]=qni(fr[i],md-2);
};
void cl(){
int n,i,j;ll r,t;scanf("%d",&n);
printf("Case #%d: ",++ct);
if(n<3){printf("0\n");return;}
r=qni(n,n);
r=(r+md-(qni(n-1,n-2)*(n-1))%md)%md;
r=(r+md-(qni(n-1,n-2)*(n-1))%md)%md;
r=(r+md-(qni(n-1,n-1)*n)%md)%md;
for(i=3,t=0;i<=n;++i)t=(t+(fr[n-1]*qn[n-i]%md*qni(n-1,n-i)%md)%md)%md;
r=(r+md-t)%md;
printf("%I64d\n",n*r%md);
};
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int t;_init();scanf("%d",&t);
while(t--)cl();
return 0;
};