传送门
不会写,完全搬的官方题解,我是fw
定义 g [ k ] g[k] g[k]为选出 k k k个盒子装不合法的方案数
设 f [ x ] = x ! f[x]=x! f[x]=x!
那么 g [ k ] ∗ f [ n − k ] g[k]*f[n-k] g[k]∗f[n−k]就代表至少 k k k个盒子不合法的方案数
那么使用容斥原理可以得到解
如何求 g [ k ] g[k] g[k]?
已知第 i i i个盒子不合法可以把对应的 c n t [ i ] cnt[i] cnt[i]个球装进来
而且因为每个球只有一个不合法的盒子,所以不合法盒子内可选择的球是不冲突的
也就是枚举第 i i i个球 g [ k ] + = g [ k − 1 ] ∗ a [ i ] g[k]+=g[k-1]*a[i] g[k]+=g[k−1]∗a[i]
两重循环就搞定了,有点类似零一背包
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 8009;
const int mod = 998244353;
int n,a[maxn],g[maxn],f[maxn];
signed main()
{
g[0] = f[0] = 1;
cin >> n;
for(int i=1;i<=n;i++) { int x; cin >> x; a[x]++; f[i] = f[i-1]*i%mod; }
for(int i=1;i<=n;i++)//枚举每个盒子
for(int j=n;j>=1;j--)
g[j] = ( g[j]+g[j-1]*a[i] )%mod;
int ans = 0;
for(int i=0,j=1;i<=n;i++,j=-1*j)
ans = ( ans+j*f[n-i]*g[i]%mod )%mod;
cout << (ans+mod)%mod;
}