• [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

    5 1 4
    1 2

    Sample Output

    13

    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$个奇点的方案数。

    易推出

    1.$f[i][j]+=f[i-1][j-2]*{C^2 _{n-j+2}}$ (第$i$条边连接了两个非奇点)

    2.$f[i][j]+=f[i-1][j]*j*(n-j)$ (第$i$条边连接一个奇点一个非奇点)

    3.$f[i][j]+=f[i-1][j+2]*{C^2 _{j+2}}$ (第$i$条边连接两个奇点)

    但除此之外,我们还没有考虑不能连接相同的边。

    由容斥原理得:

    4.$f[i][j]-=f[i-2][j]*({C^2 _n}-(i-2))$ (总共${C^2 _n}$条边,我们已经排除$i-2$条一定不重复)。

    这样$f[i][j]$的转移方程就列完了,然而,题目要求的并不是有序的我们还需要将$f[i][j]/=i$使$f$代表无序。

    综上,若$f[i][j]$表示无序地添入$i$条边后还剩$j$个奇点的方案数:

    $f[i][j] = {1 over i}(f[i-1][j-2]*{C^2 _{n-j+2}}$$+f[i-1][j]*j*(n-j)$$+f[i-1][j+2]*{C^2 _{j+2}}$$-f[i-2][j]*({C^2 _n}-(i-2)))$

     1 //It is made by Awson on 2017.9.23
     2 #include <set>
     3 #include <map>
     4 #include <cmath>
     5 #include <ctime> 
     6 #include <queue>
     7 #include <stack>
     8 #include <string>
     9 #include <cstdio>
    10 #include <vector>
    11 #include <cstdlib>
    12 #include <cstring>
    13 #include <iostream>
    14 #include <algorithm>
    15 #define Min(a, b) ((a) < (b) ? (a) : (b))
    16 #define Max(a, b) ((a) > (b) ? (a) : (b))
    17 #define LL long long
    18 using namespace std;
    19 const int N = 1000;
    20 const int MOD = 10007; 
    21 
    22 int n, m, k, u, v;
    23 bool odd[N+5];
    24 int f[N+5][N+5];
    25 
    26 int quick_pow(int a, int b) {
    27     int c = 1;
    28     while (b) {
    29         if (b&1) c = a*c%MOD;
    30         a = a*a%MOD;
    31         b >>= 1;
    32     }
    33     return c;
    34 }
    35 int C2(int n) {
    36     return n*(n-1)/2%MOD;
    37 }
    38 
    39 void work() {
    40     scanf("%d%d%d", &n, &m, &k);
    41     for (int i = 1; i <= m; i++) {
    42         scanf("%d%d", &u, &v);
    43         odd[u] = !odd[u];
    44         odd[v] = !odd[v];
    45     }
    46     int cnt = 0;
    47     for (int i = 1; i <= n; i++) cnt += odd[i];
    48     f[0][cnt] = 1;
    49     for (int i = 1; i <= k; i++)
    50         for (int j = 0; j <= n; j++) {
    51             if (j >= 2) f[i][j] = (f[i][j]+f[i-1][j-2]*C2(n-j+2)%MOD)%MOD;
    52             f[i][j] = (f[i][j]+f[i-1][j]*j%MOD*(n-j)%MOD)%MOD;
    53             if (j+2 <= n) f[i][j] = (f[i][j]+f[i-1][j+2]*C2(j+2)%MOD)%MOD;
    54             if (i >= 2) f[i][j] = (f[i][j]+MOD-f[i-2][j]*(C2(n)-(i-2))%MOD)%MOD;
    55             f[i][j] = f[i][j]*quick_pow(i, MOD-2)%MOD;
    56         }
    57     printf("%d
    ", f[k][0]);
    58 }
    59 int main() {
    60     work();
    61     return 0; 
    62 }
  • 相关阅读:
    tomcat架构分析和源码解读
    时代和命运,选择和放弃
    Python中的test测试
    python装饰器语法
    网上传言:程序员 = 宅男,程序员真的都宅吗?现实情况是这样!
    编程初学者,哪几种编程语言最值得你去学习?其实你应该这样做!
    C/C++编程笔记:《C语言》—— 数组知识详解,学编程建议收藏!
    细数程序员 10 种“辛酸与无奈”,程序员网友直言:这也太真实了!
    程序人生丨程序员的发展之路,怎样的发展决定你拥有怎样的薪资!
    程序人生丨提问环节面试官让程序员提问,五个程序员问这些,直接录取!
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/7581516.html
Copyright © 2020-2023  润新知