[BZOJ2169] 连边

问题描述

有N个点(编号1到N)组成的无向图,已经为你连了M条边。请你再连K条边,使得所有的点的度数都是偶数。求有多少种连的方法。要求你连的K条边中不能有重边,但和已经连好的边可以重。不允许自环的存在。求连边的方法数。我们只关心它模10007的余数。

输入格式

输入的第一行有三个自然数,分别表示点数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

输出格式

输出一个整数,表示连边的方法数模10007的余数

样例输入

5 1 4
1 2

样例输出

13

说明

对于20%的数据, 4≤N≤100。对于40%的数据, 4≤N≤5000。对于100%的数据,4≤N≤50000 1≤M≤10 M≤N 所有出现的整数均不超过32位含符号整数。 时间限制:1s

链接

BZOJ

解析

考虑使用动态规划的方法来实现。设\(f[i][j]\)表示当前加了\(i\)条边,还有\(j\)个点的度数为奇数。那么,考虑如何转移。每连一条边,我们就要在\(n\)个点中选择两个点。我们可以选择两个奇点,使奇点数减2。也可以选择偶点,使奇点数加2,也可以选择一奇一偶,则奇点个数不变。所以,我们有如下状态转移方程:

\[f[i][j]=f[i-1][j-2]\times C_{n-j+2}^2+f[i-1][j+2]\times C_{j+2}^2+f[i-1][j]\times C_j^2\times C_{n-j+1}^2 \]

但是,这样计数是会有重复的。一是连的边中会有重边,所以,我们需要减去上一层转移中有重边的方案。我们可以强制有两条边连在了同两个点上,其余边都不重复,即

\[f[i][j]=f[i][j]-f[i-2][j]\times (C_n^2-i+2) \]

另外一个是连边没有顺序问题,所以

\[f[i][j]=f[i][j]/i \]

代码

#include <iostream>
#include <cstdio>
#define N 1002
using namespace std;
const int mod=10007;
int n,m,k,i,j,d[N],f[N][N],C[N][N];
int read()
{
    char c=getchar();
    int w=0;
    while(c<'0'||c>'9') c=getchar();
    while(c<='9'&&c>='0'){
        w=w*10+c-'0';
        c=getchar();
    }
    return w;
}
int poww(int a,int b)
{
    int ans=1,base=a;
    while(b){
        if(b&1) ans=ans*base%mod;
        base=base*base%mod;
        b>>=1;
    }
    return ans;
}
int main()
{
    n=read();m=read();k=read();
    for(i=1;i<=m;i++){
        int u=read(),v=read();
        d[u]++;d[v]++;
    }
    C[0][0]=1;
    for(i=1;i<=n;i++){
        C[i][0]=1;
        for(j=1;j<=n;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
    }
    int cnt=0;
    for(i=1;i<=n;i++){
        if(d[i]%2) cnt++;
    }
    f[0][cnt]=1;
    for(i=1;i<=k;i++){
        for(j=0;j<=n;j++){
            if(j>=2) f[i][j]=(f[i][j]+f[i-1][j-2]*C[n-j+2][2]%mod)%mod;
            if(j<=n-2) f[i][j]=(f[i][j]+f[i-1][j+2]*C[j+2][2]%mod)%mod;
            f[i][j]=(f[i][j]+f[i-1][j]*C[j][1]%mod*C[n-j][1]%mod)%mod;
            if(i>=2) f[i][j]=(f[i][j]-f[i-2][j]*(C[n][2]-i+2+mod)%mod+mod)%mod;
            f[i][j]=f[i][j]*poww(i,mod-2)%mod;
        }
    }
    printf("%d\n",f[k][0]);
    return 0;
}
posted @ 2020-01-21 09:52  CJlzf  阅读(250)  评论(0编辑  收藏  举报