zoukankan      html  css  js  c++  java
  • 牛客.二分图染色 (组合数学,思维,递推)

    题目:传送门

    题意

     思路

    邓老师精讲

    这题有一个巧妙的转换就是,将这种二分图问题,转移到二维矩阵上。

    这里我们可以将二分图投射到一个 n * n 的矩阵上;

    题目要求给边染色,且任意两条红色边不共享端点,任意两条蓝色边不共享端点;

    那在矩阵上,问题可以转化为,在 n * n 的矩阵上放若干红色和蓝色棋子,使得任意行和列不存在颜色相同的棋子。

    我们设 F[n] 表示在 n * n 放一种颜色的棋子,使得任意行和列最多只有一个棋子的方案数。

    那么 F[n] = C(n, i) * A(n, i) (i = 0, 1, 2 .... n) ;(n行中选 i 行,有C(n, i)种,这 i 行去和 n 列中的 i 列匹配,就有 A(n, i) 种)

    那么现在有两种颜色的棋子,那么总的方案数就是 F[n] * F[n];这些方案都满足;任意行和列不存在颜色相同的棋子。

    但是,这些方案中,存在两种颜色棋子出现在同个格子的情况,这种情况需要减掉。 考虑用容斥;

    那么最终答案就是 (-1)^n * C(n, i) * A(n, i) * F[n - i] * F[n - i]   (i = 0, 1, ..... n);

    现在还存在一个问题,那就是按照上面的公式 F[n] 的预处理是需要 O(n^2) 的,显然不行,考虑如何 O(n) 递推;

    在二维矩阵上,n * n 比 (n - 1) * (n - 1) 多了 2 * n - 1 个格子,那么在这些格子上放一个棋子有 2 * n - 1 种选择,加上不放棋子这种情况,那么总的选择就有 2*n 种,总的就是 2*n*F[n-1] 种方案,需要减去一些冲突的情况。只是多放了一个棋子上去,那么最多只有一个格子会出现冲突。

    可能出现冲突的格子就是 (n - 1) * (n - 1) 矩阵上的某个格子,那么冲突的方案就是 (n - 1) * (n - 1) * F[n - 2];

    所以 F[n] = 2*n*F[n - 1] - (n - 1)^2 * F[n - 2]

    当然,如果你实在想不到怎么递推,那就只能打表找规律了。

    #include <bits/stdc++.h>
    #define LL long long
    #define ULL unsigned long long
    #define UI unsigned int
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF 0x3f3f3f3f
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    #define lb(x) ((x) & (-(x)))
    #define dbg(x) cout<<#x<<" = "<<x<<endl;
    using namespace std;
    
    const int N = 1e7 + 5;
    
    const LL mod = 1e9 + 7;
    
    LL fac[N], ifac[N], f[N];
    
    LL ksm(LL a, LL b) {
    
        LL res = 1LL;
    
        while(b) {
    
            if(b & 1) res = res * a % mod;
    
            a = a * a % mod; b >>= 1;
    
        }
    
        return res;
    
    }
    
    LL C(int n, int m) {
    
        return fac[n] * ifac[m] % mod * ifac[n - m] % mod;
    
    }
    
    LL A(int n, int m) {
    
        return fac[n] * ifac[n - m] % mod;
    
    }
    
    int n;
    
    void solve() {
    
        scanf("%d", &n);
    
        fac[0] = ifac[0] = 1LL;
    
        rep(i, 1, n) fac[i] = 1LL * i * fac[i - 1] % mod;
    
        ifac[n] = ksm(fac[n], mod - 2);
    
        dep(i, 1, n - 1) ifac[i] = 1LL * (i + 1) * ifac[i + 1] % mod;
    
        f[0] = 1LL; f[1] = 2LL;
    
        rep(i, 2, n) f[i] = (2LL * i * f[i - 1] % mod - 1LL * (i - 1LL) * (i - 1LL) % mod * f[i - 2] % mod + mod) % mod;
    
        LL ans = 0LL;
    
        rep(i, 0, n) {
    
            if(i & 1) {
    
                ans = (ans - C(n, i) * A(n, i) % mod * f[n - i] % mod * f[n - i] % mod + mod) % mod;
    
            }
    
            else ans = (ans + C(n, i) * A(n, i) % mod * f[n - i] % mod * f[n - i] % mod) % mod;
    
        }
    
        printf("%lld
    ", ans);
    
    }
    
    
    int main() {
    
    //    int _; scanf("%d", &_);
    //    while(_--) solve();
    
        solve();
    
        return 0;
    }
  • 相关阅读:
    【记中关村.西北食府.兰州拉面】诗一首
    【新发地寻柑桔收购商】 诗一首
    【糖葫芦】诗一首
    【板栗饼】诗一首
    【白云观寻道】诗一首
    Android开发常用网站汇总
    BZOJ 2281 消失之物
    BZOJ 2281 消失之物
    BZOJ 4033: [HAOI2015]树上染色
    BZOJ 4033: [HAOI2015]树上染色
  • 原文地址:https://www.cnblogs.com/Willems/p/13690716.html
Copyright © 2011-2022 走看看