寶石裝箱(容斥原理)

寶石裝箱(容斥原理)

傳送門

ans==anssumansnoans=總方案數-不可行的方案數=ans_{sum}-ans_{no}

anssum=ans_{sum}=總方案數=n!=n!

設集合dp[i]dp[i]爲選ii個箱子裝不合法寶石的方案數,a[i]a[i]爲第ii個箱子不能裝的寶石數。

類比揹包可得遞推式:dp[i]=dp[i]+dp[i1]×a[i]dp[i]=dp[i]+dp[i-1]\times a[i]

AiA_i爲至少ii個箱子不合法的方案數。

Ai=dp[i]×(ni)!A_i=dp[i]\times(n-i)!

則有不可行的方案數=ansno=ans_{no}=A1A2A3An=|A_1\cup A_2\cup A_3\dots\cup A_n|

根據容斥原理有:ansno=k=1n(1)k1×dp[k]×(ki)!ans_{no}=\sum\limits_{k=1}^n(-1)^{k-1}\times dp[k]\times(k-i)!

ans=anssumansno =n!k=1n(1)k1×dp[k]×(nk)!ans=ans_{sum}-ans_{no}\ =n!-\sum\limits_{k=1}^n(-1)^{k-1}\times dp[k]\times(n-k)!

n!=(1)0×dp[0]×n!n!=(-1)^0\times dp[0]\times n!

所以ans=k=0n(1)k×dp[k]×(nk)!ans=\sum\limits_{k=0}^{n}(-1)^k\times dp[k]\times(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;
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章