BZOJ 4665 小w的喜糖

2022-05-19 11:02:15 字數 1565 閱讀 5693

傳送門

見計數想容斥

顯然每個人交換後可以變成任意的排列

所以就是求對於所有排列使得每個位置的值都和一開始的值不同

感覺同乙個值算同乙個數不太好搞,考慮把所有數都看成不同的,最後答案再除 $\prod _^fac[cnt[i]]$(其中 $cnt[i]$ 表示值為 $i$ 的數的個數)

然後發現每個位置都要不同的限制很麻煩,

考慮先求出 $f[i]$ 表示至少有 $i$ 個位置拿到原來的數的方案數

考慮 $dp$ 這個東西,設 $f[i][j]$ 表示已經選好從 $1$ 到 $i$ 的數的位置,當前有 $j$ 個位置是原來的數,其他的位置還沒考慮

那麼考慮直接列舉這個值 $i$ 有 $k$ 個數還在原來的位置,$k \in [0,cnt[i]]$

那麼有 $f[i][j]=\sum_^f[i-1][j-k]c_^ (\prod_^p)$(就是我隨便選出 $k$ 個位置,然後隨便放在那 $cnt[i]$ 個位置上)

求出 $f[i][j]$ 以後那麼 $f[i]=f[n][i]*(n-i)!$

然後容斥一下,$ans=\sum_^(-1)^if[i]$

別忘了最後要除乙個 $\prod _^fac[cnt[i]]$

#include#include

#include

#include

#include

using

namespace

std;

typedef

long

long

ll;inline

intread()

while(ch>='

0'&&ch<='

9')

return x*f;

}const

int n=2007,mo=1e9+9

;inline

int fk(int x)

intn,m,a[n],cnt[n],ans;

intfac[n],inv[n],facinv[n],c[n][n],f[n][n];

intmain()

c[0][0]=1

;

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

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

f[0][0]=1

;

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

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

for(int k=0;k<=cnt[i]&&k<=j;k++)

f[i][j]=fk( f[i][j]+ 1ll*f[i-1][j-k]*c[cnt[i]][k]%mo *fac[cnt[i]]%mo *facinv[cnt[i]-k]%mo );

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

for(int i=1;i<=n;i++) ans=1ll*ans*facinv[cnt[i]]%mo;

printf("%d

",ans);

return0;

}

BZOJ4665 小w的喜糖

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

BZOJ 4665 小w的喜糖

題鏈 題解 容斥,dp 令 v i 表示原來擁有i類糖果的人數。乙個套路,首先把每個糖果看成互不相同的,最後再來除以 v i 把同種糖果看成相同的 定義 dp i j 表示前i類糖果,有j個人的糖果和原來的一樣,其他 n j 個人暫時不拿糖果的方案數。這個的轉移如下 對於已經確定的 i,j,列舉乙個...

BZOJ4665 小w的喜糖 DP

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