同色不相鄰的方案數求解

2022-04-29 19:54:09 字數 2297 閱讀 8657

有\(n\)種顏色的小球,

每種顏色的小球有\(a_i\)個,即一共有\(\sum_^n a_i\)個小球。

現在要求把這些小球排同色不相鄰的方案數求解成一行,要求同種顏色的小球不相鄰

求方案數,答案對\(10^9+7\)取模。 提交**:web

下面的演算法都只考慮同色小球之間無區別的方案數。

可重排列的情況。

如果同色小球之間有區別,為不重排列,那麼對應乘上 \(\prod (a_i!)\) 即可。

從前往後列舉每種顏色的小球。

設\(f_\)表示考慮完前\(i\)種小球,存在\(j\)個違法相鄰的方案數。

轉移首先考慮將\(a_i\)個小球分為\(k\)段,一共\(\binom\)種方法。

這一共造成了\(a_i - k\)個新的不合法情況。

列舉把其中\(l\)塊插入原先的不合法位置之間,那麼一共消除了\(l\)個不合法相鄰。

這一共有\(\binom\)種選擇,剩下的塊有\(\binom\)種選擇。

所以轉移方程式:

\[f_ = \sum f_ \binom \binom \binom

\]其中\(sum = \sum_^ a_e\) ;

滿複雜度:\(o(n(\sum a)a_^2)\),但是非常不滿,實測跑 \(n,\sum a\leq 1000\)並不虛。

這種方法好寫好理解,但是適用性較窄(不方便新增整段權值)。

#include#define ll long long

#define maxn 2005

#define mod 1000000007

using namespace std;

ll n , q, x , sum , cur;

ll a[maxn] , fac[maxn] , c[maxn][maxn] , f[3][maxn];

void pre()

return;

}int main()

sum += a[i];

}cout《全部不相鄰的方案數 = 全部不相臨的排列數 - 1個相鄰的排列數 + 2個相鄰的排列數 ......

直接列舉不好算,單獨考慮一種小球的貢獻。

由於可重排列:\(p = \frac\),所以先只乘\(\frac\),最後乘上\((\sum a)!\)即可。

我們可以列出有\(a_i\)個小球的容斥多項式:

\[f(a_i) = \sum_ ^ (-1)^ \frace(a_i , i)

\]其中\(e(i,j)\)表示\(i\)個小球因為違法相鄰而實際只有\(j\)段的方案數。

顯然就是要保留\(i-1\)個間隔中的\(j-1\)個,所以\(e(i,j) = \binom\)。

把每種小球的容斥多項式卷積卷起來就可以得到總的容斥式。

對於最後的總容斥式的每一項,乘上對應的階乘(可重排列的分子),再加起來即可。

總時間複雜度:\(o(n(\sum a)a_)\)。

這種做法較難理解、容易寫錯,但是複雜度低,適用性好(新增權值直接在計算係數時乘上即可)。

//#include#define rg register

#define il inline

#define n 505

using namespace std;

const int mod = 1000000007 ;

int dp[10*n],c[n+5][n+5],e[n+5][n+5],fact[n+5],a[n+5],n,sum,ans;

int inv[n+5],inv_fact[n+5],coef[n+5];

il void pre()return ;

}il void upt(rg int &x,rg int y)

int main()

sum += a[sq]; //dp記錄的是最後的總容斥式的每一項係數.

} ans = 0;

for(rg int k = 0; k <= sum; k ++) upt(ans , 1ll * dp[k] * fact[k] % mod) ;

printf("%d\n" , ans) ; return 0;

}

不相鄰的組合個數

a 中選取m m個不相鄰的組合個數,即不存在兩個數j和j 1的組合。例如,n 4 m 2 n 4,m 2 有組合,a 中取mm 個不相鄰組合,其組合數為cmn m 1 cn m 1m。b 是一組不相鄰的組合,假設b 1 b1,令c1 b1,c 2 b2 1,c 3 b3 2,cm bm m 1 n ...

Python從列表中刪除相鄰和不相鄰的相同元素

相鄰元素是不相鄰元素中的一種特殊的存在,所以我們先來 不相鄰的相同元素的刪除。結果 list 1,2,3,4 第一種 list 1,2,3,3,4,1,1 new list for i in list if i not in new list 可以刪除重複元素,不管是否相鄰 print new li...

求不相鄰的最大子陣列和

參考 題目 給定乙個陣列a,求出一些數,使得每個元素在陣列a裡兩兩不相鄰,並且和最大。選擇第i個元素,那麼第i 1個元素一定不能選 不選擇第i個元素,那麼第二個元素既可以選,也可以不選 includeusing namespace std int main int selected 8 int no...