牛客练习赛64 D.宝石装箱 【容斥原理+背包DP】

传送门

题解

转载自官方题解
\(g(x)\) 表示选定 \(x\) 个箱子装不合法的宝石的方案数。
\(f(x)=x!\) 表示选 \(x\) 个箱子任意装宝石的方案数。
那么 \(g(x)*f(n-x)\) 表示至少 \(x\) 个箱子装了不合法宝石的方案数。
根据容斥原理,答案为 \(\sum_{i=0}^n(-1)^i*g(i)*f(n-i)\)
\(a_i\) 表示不可以装入 \(i\) 箱子的宝石的数量,因为一个宝石对应一个箱子,每个箱子不可以装的宝石不会有重叠。
初始时,\(g(0)=1,g(i)=0\)
然后相当于每次加入一个物品,当加到 \(i\) 号箱子,有 \(g(k)=g(k-1)*a_i\),就可以通过背包求出 \(g\) 了。
复杂度 \(O(n^2)\)

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N=8010;
const int mod=998244353;
int n,a[N];
LL fac[N]={1},f[N]={1};

int main(){
    scanf("%d",&n);
    for(int i=1,x;i<=n;i++){
        scanf("%d",&x),a[x]++;
        fac[i]=fac[i-1]*i%mod;
    } 
    for(int i=1;i<=n;i++)
        for(int j=n;j>=1;j--)
            (f[j]+=f[j-1]*a[i])%=mod;
    LL ans=0;
    for(int i=0,j=1;i<=n;i++,j*=-1) (ans+=1ll*j*f[i]*fac[n-i])%=mod;
    printf("%lld\n",(ans+mod)%mod); 
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/BakaCirno/p/12941419.html