zoukankan      html  css  js  c++  java
  • nowcoder-204323 宝石装箱 (容斥原理,dp)

    题目链接:nowcoder-204323 宝石装箱

    题意

    (n) 颗宝石装进 (n) 个箱子使得每个箱子中都有一颗宝石,第 (i) 颗宝石不能装入第 (a_i) 个箱子,求合法的装箱方案数对 (998244353) 取模。两种装箱方案不同当且仅当两种方案中存在一颗编号相同的宝石装在不同编号的箱子中。( (1leq a_i leq n leq 8000) )


    思路

    这道题正向思考不容易求解,利用反向思维:一共有 (n!) 个排列,把不合法的方案数减去,就是合法的方案数。

    不合法的方案数可以这样求:

    (cnt[i]) 表示有 (cnt[i]) 个宝石不能装入第 (i) 个箱子。这 (cnt[i]) 个宝石选 (1) 个放在第 (i) 个箱子有 (cnt[i]) 种方案,剩下的 (n-1) 个宝石有 ((n-1)!) 种排列,那么第 (i) 个箱子放的宝石不合法的方案数就是 ((n-1)!cdot cnt[i]) 种。

    选定 (1) 个箱子装的宝石不合法的方案数共有:(f_1 = (n-1)!cdotsum_{i=1}^n cnt[i])

    选定 (2) 个箱子装的宝石不合法的方案数共有:(f_2=(n-2)!cdot sum_{i=1}^n sum_{j=i+1}^ncnt[i]cdot cnt[j])

    选定 (3) 个箱子装的宝石不合法的方案数共有:(f_3=(n-3)!cdotsum_{i=1}^nsum_{j=i+1}^nsum_{k=j+1}^ncnt[i]cdot cnt[j]cdot cnt[k])

    ......

    里面的和式可以通过二维 dp 预处理,令 (dp[i][j]) 表示前 (i)(cnt) ,取 (j) 个的乘积之和,即 (f_i=(n-i)!cdot dp[n][i]) ,则:(dp[i][j]=dp[i-1][j]+dp[i-1][j-1]cdot cnt[i])

    记至少有 (1) 个箱子装的宝石不合法的方案数为 (f)(f_1) 是否就是 (f) ?我们选定第 (i) 个箱子放的宝石不合法时,其他宝石是随意排列的,也就包含了其他宝石放置不合法的情况;再选定其他箱子放的宝石不合法时,也会包含第 (i) 个箱子宝石不合法的情况,这就重复计算了。所以 (f_1 e f),利用容斥原理,有 (f=sum_{i=1}^n(-1)^{i-1}f_i) ,最终答案为 (n!-f)


    代码实现

    #include <cstdio>
    typedef long long LL;
    const int maxn = 8010, mod = 998244353;
    LL dp[2][maxn], f[maxn];
    int cnt[maxn];
    
    int main() {
        int n;
        scanf("%d", &n);
        f[0] = 1;
        for (int i = 1, x; i <= n; i++) {
            scanf("%d", &x);
            cnt[x]++;
            f[i] = f[i-1] * i % mod;
        }
        dp[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            dp[i&1][0] = 1;
            for (int j = 1; j <= i; j++) {
                dp[i&1][j] = (dp[(i-1)&1][j] + dp[(i-1)&1][j-1] * cnt[i]) % mod;
            }
        }
        LL ans = f[n];
        for (int i = 1; i <= n; i++) {
            if (i & 1) ans = (ans - f[n-i] * dp[n&1][i] % mod + mod) % mod;
            else ans = (ans + f[n-i] * dp[n&1][i]) % mod;
        }
        printf("%lld
    ", ans);
    
        return 0;
    }
    
  • 相关阅读:
    centos7.x网卡bond配置
    twemproxy源码解析系列三Twemproxy配置文件解析及相关组件初始化过程
    twemproxy源码解析系列二关键数据结构分析
    Nginx 变量漫谈(一)(转)
    twemproxy源码解析系列一特性及启动流程分析
    理解 Linux 的处理器负载均值
    man命令使用
    awk 查找文件中数字 字符串 email
    非阻塞socket调用connect, epoll和select检查连接情况示例
    Mysql日期类型大小比较拉取给定时间段的记录
  • 原文地址:https://www.cnblogs.com/kangkang-/p/12940634.html
Copyright © 2011-2022 走看看