BZOJ4665 小w的喜糖 容斥 組合數

2022-05-20 07:53:01 字數 1475 閱讀 7932

廢話不多說,反正小w要發喜糖啦!!

小w一共買了n塊喜糖,發給了n個人,每個喜糖有乙個種類。這時,小w突發奇想,如果這n個人相互交換手中的糖,那會有多少種方案使得每個人手中的糖的種類都與原來不同。

兩個方案不同當且僅當,存在乙個人,他手中的糖的種類在兩個方案中不一樣。

第一行,乙個整數n

接下來n行,每行乙個整數,第i個整數ai表示開始時第i個人手中的糖的種類

對於所有資料,1≤ai≤k,k<=n,n<=2000

一行,乙個整數ans,表示方案數模100000000961

1223

310題解:顯然我們應該將每種糖果放在一起處理,用v[i]表示有多少人有第i種糖果。然後考慮容斥,用f[i][j]表示前i種糖果,至多j個人的糖果與原來不同的方案數,然後很容易dp求出f陣列。

$f[i][j]=\sum\limits_^f[i-1][j-k]*c_^*(v[i])*(v[i]-1)*...*(v[i]-k+1)$

發現我們在dp過程中並沒有考慮我們選出來那j個人的順序,所以最後f[i][j]乘上j!即可。最後因為每個糖果是相同的,所以方案數要除以v[i]!。

#include #include #include #include using namespace std;

typedef long long ll;

const ll p=1000000009;

int n,m;

ll ans;

int col[2010],s[2010],v[2010];

ll c[2010][2010],f[2010][2010],jc[2010],ine[2010],jcc[2010];

inline int rd()

while(gc>='0'&&gc<='9') ret=ret*10+gc-'0',gc=getchar();

return ret*f;

}int main()

jc[0]=ine[0]=jcc[0]=jc[1]=ine[1]=jcc[1]=1;

for(i=2;i<=n;i++)

for(i=1;i<=n;i++) col[i]=rd();

sort(col+1,col+n+1);

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

for(i=1;i<=m;i++) s[i]=s[i-1]+v[i];

f[0][0]=1;

for(i=1;i<=m;i++) for(j=0;j<=s[i-1];j++) for(k=0;k<=v[i];k++)

f[i][j+k]=(f[i][j+k]+f[i-1][j]*c[v[i]][k]%p*jc[v[i]]%p*jcc[v[i]-k]%p)%p;

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

for(i=1;i<=m;i++) ans=ans*jcc[v[i]]%p;

printf("%lld",ans);

return 0;

}

BZOJ 4665 小w的喜糖 dp,容斥

qwq做的第一發這種題 f i j 表示分配了前i種,至少有j個人不合法,然後容斥一下就好 最後統計的時候,剩下的n j個人的分配方法是 n j 除以每種糖剩餘數量的階乘的積,這個積直接在dp的時候算好 include define mod 1000000009 define maxn 2005 u...

bzoj4665 小w的喜糖(dp 容斥)

time limit 10 sec memory limit 128 mb submit 222 solved 130 submit status discuss 廢話不多說,反正小w要發喜糖啦!小w一共買了n塊喜糖,發給了n個人,每個喜糖有乙個種類。這時,小w突發奇想,如果這n個人相互交換手中的糖...

BZOJ4665 小w的喜糖

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