• AcWing 1309. 车的放置


    题目传送门

    算法分析

    规则后的图形

    题目给定的图片是不规则图形,我们可以将它分解成若干个规则图形,因为规则图形可以通过公式直接计算出来,如上图所示,对于某个规则的矩形,长度是a,宽度是b,放k辆车(k <= b <= a),在长度是a行中任选k行进行摆放,共有b列,第一辆车有b种摆放方案,第二辆车有b - 1中摆放方案…,第k辆车有b - k + 1种摆放方案,因此一共有\(\displaystyle C_a^kP_b^k\)种摆放方案

    您是对\(C_b^iP_a^i\)中的\(P_a^i\)有疑问吗,最开始我认为\(P_a^i\)应该是\(C_a^i\),后来发现想错的点是因为我认为是从a列里面随便选i列即可,不需要顺序,所以是\(C_a^i\),但是在每一列里面,车究竟在哪一行,是没有考虑到的,所以我们应该在选好了用哪些行以后,针对每一行来看安排在哪一列,若矩阵是\(3*4\)的,我们选择了第一行和第二行,然后我们需要在第一行选择一列,有四种选择,在第二行,有三种选择,所以是\(P_4^2\).也就是说\((1,3),(2,4)与(1,4),(2,3)\)是不同的选择

    分解图形(按照红线位置划分成两个矩形)

    上半部分摆放i辆车,有\(\displaystyle C_b^iP_a^i\)种摆放方案

    下半部分摆放k - i辆车,由于上半部分摆放了i辆车,占用的列对下半部分选择有了一定的影响,即占用的列对于下半部分是不可使用的,因此从d行中选k - i行,有a + c - i列可以进行摆放并摆放k - i辆车,因此有 \(C_d^{k-i}P_{a+c-i}^{k-i}\) 种摆放方案

    由于上半部分的摆放情况 和 下半部分的摆放情况是相互独立的,因此可以使用乘法原理,上半部分摆放i辆车,整张图的摆放方案是

    \[\large C_b^{i}P_a^iC_d^{k-i}P_{a+c-i}^{k-i} \]

    时间复杂度 \(O(Nlogmod)\)
    \(N = 2000\)\(mod = 100003\)

    实现代码

    #include <bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    
    const int N = 2010, mod = 100003; //因为式子中出现a+c,所以N要开两倍
    
    int fact[N], infact[N]; //阶乘与阶乘的逆元
    //快速幂模板
    int qmi(int a, int k, int p) {
        int res = 1;
        while (k) {
            if (k & 1) res = (LL)res * a % p;
            a = (LL)a * a % p;
            k >>= 1;
        }
        return res;
    }
    
    //组合数
    int C(int a, int b) {
        if (a < b) return 0;
        // C(a,b)=a!/(a-b)! % mod
        return (LL)fact[a] * infact[a - b] % mod * infact[b] % mod;
    }
    
    //排列数
    int P(int a, int b) {
        if (a < b) return 0;
        // P(a,b)=a!/(a-b)!
        return (LL)fact[a] * infact[a - b] % mod;
    }
    
    int main() {
        //组合数公式II
        //预处理出阶乘和阶乘的逆元
        fact[0] = infact[0] = 1; // 0的阶乘是1,这是人为的规定。 1/1也是1,infact[0]也是1
        for (int i = 1; i < N; i++) {
            fact[i] = (LL)fact[i - 1] * i % mod;                        //阶乘
            infact[i] = (LL)infact[i - 1] * qmi(i, mod - 2, mod) % mod; //因为100003是质数,可以用费马小定理求出阶乘的逆元
        }
    
        int a, b, c, d, k;
        cin >> a >> b >> c >> d >> k;
    
        int res = 0;
        for (int i = 0; i <= k; i++) //在上面的矩阵中,放i个,但要注意C(a,b),P(a,b)中a>=b,这里处理的也非常巧妙,
                                     //没有在计算时进行特判,而是在实现C函数、P函数时进行了特判,if(a<b) return 0;
            res = (res + (LL)C(b, i) * P(a, i) % mod * C(d, k - i) % mod * P(a + c - i, k - i)) % mod;
    
        cout << res << endl;
        return 0;
    }
    
    
  • 相关阅读:
    追踪路由信息
    Windows Server 2008 R2远程桌面服务安装配置和授权激活
    CentOS 7 下挂载NTFS盘及开机自动挂载
    functools 之 partial(偏函数)
    Flask-WTForms 简单使用
    Flask-Session 简单使用
    通过decorators = [,] 的形式给类中的所有方法添加装饰器
    Python __dict__属性详解
    面向对象的 __slots__
    related_name和related_query_name举例区别
  • 原文地址:https://www.cnblogs.com/littlehb/p/16352043.html
Copyright © 2020-2023  润新知