​传送门​

不会写,完全搬的官方题解,我是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;
}