[BZOJ 2169]连边
Description
有N个点(编号1到N)组成的无向图,已经为你连了M条边。请你再连K条边,使得所有的点的度数都是偶数。求有多少种连的方法。要求你连的K条边中不能有重边,但和已经连好的边可以重。不允许自环的存在。求连边的方法数。我们只关心它模10007的余数。
Input
输入的第一行有三个自然数,分别表示点数N,已经连好的边数M,和你要连的边数K。保证K≤N(N-1)/2 接下来M行每行两个整数x,y,描述了一条连接x和y的边。 30%的数据满足: N≤200 100%的数据满足: N≤1000,M≤N,K≤1000,K≤N(N-1)/2
Output
输出一个整数,表示连边的方法数模10007的余数
Sample Input
1 2
Sample Output
HINT
【样例说明】
以下是13种连边的方法(只显示你连的边):
{(1,2),(1,3),(1,4),(3,4)}
{(1,2),(1,3),(1,5),(3,5)}
{(1,2),(1,4),(1,5),(4,5)}
{(1,2),(2,3),(2,4),(3,4)}
{(1,2),(2,3),(2,5),(3,5)}
{(1,2),(2,4),(2,5),(4,5)}
{(1,2),(3,4),(3,5),(4,5)}
{(1,3),(2,4),(3,5),(4,5)}
{(1,3),(2,5),(3,4),(4,5)}
{(1,4),(2,3),(3,5),(4,5)}
{(1,4),(2,5),(3,4),(3,5)}
{(1,5),(2,3),(3,4),(4,5)}
{(1,5),(2,4),(3,4),(3,5)}
令f[i][j]表示加i条边,j个奇点的方案
f[i][j]+=f[i-1][j-2]*C(n-j+2,2)
f[i][j]+=f[i-1][j]*(n-j)*j
f[i][j]+=f[i-1][j+2]*C(j+2,2)
还要减去重复的方案:
f[i][j]-=f[i-2][j]*(C(n,2)-i+2)
因为是有序的,转为无序的
f[i][j]/=i;
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 int du[1001],cnt,n,m,k; 7 int Mod=10007; 8 long long f[1001][1001],A[1001]; 9 long long C(int x) 10 { 11 if (x<2) return 0; 12 return (x-1)*x/2; 13 } 14 int main() 15 {int i,j,u,v; 16 cin>>n>>m>>k; 17 A[0]=1;A[1]=1; 18 for (i=2;i<=1000;i++) 19 A[i]=(Mod-Mod/i)*A[Mod%i]%Mod; 20 for (i=1;i<=m;i++) 21 { 22 scanf("%d%d",&u,&v); 23 du[u]++;du[v]++; 24 } 25 for (i=1;i<=n;i++) 26 if (du[i]%2==1) cnt++; 27 f[0][cnt]=1; 28 for (i=1;i<=k;i++) 29 { 30 for (j=0;j<=n;j++) 31 { 32 if (j>=2) 33 f[i][j]+=f[i-1][j-2]*C(n-j+2)%Mod; 34 f[i][j]%=Mod; 35 if (j+2<=n) 36 f[i][j]+=f[i-1][j+2]*C(j+2)%Mod; 37 f[i][j]%=Mod; 38 f[i][j]+=f[i-1][j]*j*(n-j)%Mod; 39 f[i][j]%=Mod; 40 if (i>=2) 41 f[i][j]-=f[i-2][j]*(C(n)-i+2)%Mod; 42 f[i][j]=(f[i][j]+Mod)%Mod; 43 f[i][j]*=A[i];f[i][j]%=Mod; 44 } 45 } 46 cout<<f[k][0]; 47 }