寶石裝箱(容斥原理)
傳送門
ans=總方案數−不可行的方案數=anssum−ansno
anssum=總方案數=n!
設集合dp[i]爲選i個箱子裝不合法寶石的方案數,a[i]爲第i個箱子不能裝的寶石數。
類比揹包可得遞推式:dp[i]=dp[i]+dp[i−1]×a[i]
令Ai爲至少i個箱子不合法的方案數。
則Ai=dp[i]×(n−i)!
則有不可行的方案數=ansno=∣A1∪A2∪A3⋯∪An∣
根據容斥原理有:ansno=k=1∑n(−1)k−1×dp[k]×(k−i)!
即ans=anssum−ansno =n!−k=1∑n(−1)k−1×dp[k]×(n−k)!
n!=(−1)0×dp[0]×n!
所以ans=k=0∑n(−1)k×dp[k]×(n−k)!
AC代碼:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=8e3+10,mod=998244353;
#define mst(a) memset(a,0,sizeof a)
int n;
ll dp[N]={1},a[N],f[N]={1};
int main(){
scanf("%d",&n);
for(int i=1,x;i<=n;i++)
scanf("%d",&x),a[x]++,f[i]=f[i-1]*i%mod;
for(int i=1;i<=n;i++)
for(int j=i;j>=0;j--)
dp[j+1]=(dp[j+1]+dp[j]*a[i])%mod;
ll ans=0;
for(int i=0,p=1;i<=n;i++,p*=-1)
ans=(ans+dp[i]*p*f[n-i]%mod)%mod;
ans=(ans+mod)%mod;
printf("%lld\n",ans);
return 0;
}