BZOJ 4665 小w的喜糖

2022-03-18 04:19:47 字數 1373 閱讀 8860

題鏈:

題解:

容斥,dp

令 v[i] 表示原來擁有i類糖果的人數

(乙個套路,首先把每個糖果看成互不相同的,(最後再來除以 v[i]!,把同種糖果看成相同的))

定義 dp[i][j]表示前i類糖果,有j個人的糖果和原來的一樣,其他 n-j 個人暫時不拿糖果的方案數。

這個的轉移如下:

對於已經確定的 i,j,列舉乙個 k表示原來擁有的是第i類糖果的k個人任然拿到的是第i類糖果。

$\times_^}\times\times\times\times$

式子後面乘的東西意思是那k個人在第i類糖果中的選擇方法數(每個糖果看成不一樣的了)

然後就再把每乙個 dp[n][i] * (n-i)! 表示剩下的人就隨便選擇糖果。

此時 dp[n][i]的含義即為:重新分配糖果後,至少有 i個人拿到了原來的那類糖果的方法數。

然後就是考慮容斥,答案 ans=dp[n][0]-dp[n][1]+dp[n][2]-dp[n][3]......

最後還要把同類糖果看成相同的東西,即 ans/=v[i]。

**:

#include#include#include#define maxn 2500

#define _ %mod

#define filein(x) freopen(#x".in","r",stdin)

#define fileout(x) freopen(#x".out","w",stdout)

using namespace std;

const int mod=1000000009;

int v[maxn],dp[maxn][maxn],c[maxn][maxn],fac[maxn],inv[maxn];

int n,ans;

int pow(int a,int b)

return now;

}int main()

for(int i=1,x;i<=n;i++) scanf("%d",&x),v[x]++;

dp[0][0]=1;

for(int i=1;i<=n;i++)

for(int j=0;j<=n;j++)

for(int k=0;k<=v[i];k++)

for(int i=0;i<=n;i++)

for(int i=1;i<=n;i++) ans=1ll*ans*inv[v[i]]_;

printf("%d",ans);

return 0;

}

BZOJ4665 小w的喜糖

考慮列舉哪些人一定不合法,那麼方案數可以通過簡單的排列組合算出。於是設 f i j 表示前 i 種糖果,一共有 j 個人一定不合法的方案數,但是這樣並不能保證其他人一定合法,所以需要進行容斥。最後將答案除以每種糖果數量的階乘,即可保證本質不同。時間複雜度 o n 2 includeconst int...

BZOJ 4665 小w的喜糖

傳送門 見計數想容斥 顯然每個人交換後可以變成任意的排列 所以就是求對於所有排列使得每個位置的值都和一開始的值不同 感覺同乙個值算同乙個數不太好搞,考慮把所有數都看成不同的,最後答案再除 prod fac cnt i 其中 cnt i 表示值為 i 的數的個數 然後發現每個位置都要不同的限制很麻煩,...

BZOJ4665 小w的喜糖 DP

對於這道題,首先每個人的位置並不影響結果 所以我們可以將相同顏色糖果的人放在一塊處理 設 f 表示處理到第 i 種糖果至少有 j 人的糖果和原先的型別相同 列舉當前種類中不滿足要求的個數 則有 f sum f binom dfrac k ans sum n n i c i 表示第 i 種糖的個數,這...