XSY3156 簡單計數II 容斥 DP

2022-03-25 17:28:13 字數 2277 閱讀 7107

定義乙個序列的權值為:把所有相鄰的相同的數合併為乙個集合後,所有集合的大小的乘積。

特別的,第乙個數和最後乙個數是相鄰的。

現在你有 \(n\) 種數,第 \(i\) 種有 \(c_i\) 個。求所有不同的序列的權值的和。

\(n\leq 50,c_i\leq 100\)

考慮第乙個數和最後乙個數不相鄰時怎麼做。

記 \(g_\) 為出現了 \(i\) 次的數分成 \(j\) 個集合,所有集合大小的乘積的和。

\[g_=\sum_^ig_\times k

\]假設最後 \(i\) 分成了 \(a_i\) 個集合,那麼答案就是 \(\prod_^ng_\) 再乘上方案數。

方案數可以容斥求。

具體來說,把最後相鄰且同色的球合併成乙個大球。設最後有 \(b_i\) 個大球,那麼容斥係數就是 \(^\),帶容斥係數的方案數就是 \(\binom^\)

最後這 \(\sum b_i\) 個球可以隨意放,方案數是 \(\frac\)

總的答案是

\[\left(\prod_^ng_\binom^\right)\frac^nb_i)!}^n b_i!}

\]這樣就可以 dp 了。(狀態為 \(i\) 和 \(\sum b_i\))

考慮第乙個數和最後乙個數相鄰時怎麼做。

可以用最小表示法,令第乙個數為 \(1\) 且 最後乙個數不為 \(1\)(除非 \(n=1\))。

只需要在後面計算組合數的時候把 \(b_1-1\) 再除以 \(a_1\) 就可以得到第乙個數為 \(1\) 的方案數。

把 \(b_1-2\) 再除以 \(a_1\) 就可以得到第乙個數為 \(1\) 且最後乙個數也是 \(1\) 的方案數。

除以 \(a_1\) 是因為乙個方案會被算多次。

再把方案數乘以 \(\sum c_i\) 就是答案了。

時間複雜度:\(o((\sum c_i)^2)\)

#include#include#includeusing namespace std;

typedef long long ll;

const ll p=1000000007;

ll fac[5010],ifac[5010],inv[5010];

ll f[60][5010];

ll g[110][110];

int a[60];

int n;

int s[60];

ll c[110][110];

ll c1[110],c2[110];

ll binom(int x,int y)

int main()

inv[1]=fac[0]=fac[1]=ifac[0]=ifac[1]=1;

for(int i=2;i<=5000;i++)

g[0][0]=1;

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

for(int j=1;j<=100;j++)

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

g[i][j]=(g[i][j]+g[i-k][j-1]*k)%p;

f[0][0]=1;

for(int i=1;ifor(int j=1;j<=a[i];j++)

for(int k=1;k<=j;k++)

c[i][k]=(c[i][k]+g[a[i]][j]*binom(j-1,k-1)%p*((j-k)&1?-1:1))%p;

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

for(int j=1;j<=a[i];j++)

for(int k=1;k<=j;k++)

c1[k]=(c1[k]+g[a[i]][j]*binom(j-1,k-1)%p*((j-k)&1?-1:1)*inv[j])%p;

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

for(int j=1;j<=a[i];j++)

for(int k=0;k<=s[i-1];k++)

f[i][k+j]=(f[i][k+j]+f[i-1][k]*c[i][j]%p*binom(k+j,k))%p;

ll ans=0;

for(int j=1;j<=a[n];j++)

for(int k=0;k<=s[n-1];k++)

ans=(ans+f[n-1][k]*c1[j]%p*(binom(k+j-1,k)-binom(k+j-2,k)))%p;

ans=ans*s[n]%p;

ans=(ans+p)%p;

printf("%lld\n",ans);

return 0;

}

XSY3952 簡單的計數題(dp)

簡單的計數題 首先題意可以轉化為 給你乙個長度為 n nn 的序列 c cc,求將 c cc 分成兩個長度為 n 2 dfrac 2n 的相同的子串行的方案數。考慮 dp,設 f i sta f i,sta f i,st a 表示已經將 c cc 的前 i ii 位分成了兩個子串行,其中長的子串行比...

教你python tkinter實現簡單計算器功能

這篇文章主要為大家詳細介紹了python tkinter實現簡單計算器功能,文中示例 介紹的非常詳細,具有一定的參考價值,感興趣的小夥伴們可以參考一下 效果圖 直接上 import tkinter as tk input num ls first num none calculator method...

編譯原理利用Flex Bison實現簡單計算器

編譯原理利用flex bison實現簡單計算器 一 實驗目的 1 掌握 yacc 的基本用法,並能夠根據語言給出語法規則的定義,最後生成語言的解析器 2 使用使用 yacc 實現乙個高階計算器程式 二 實驗內容 實現乙個簡單的表示式計算器,要求能進行加 減 乘 除 冪運算,注意優先順序。寫出詳細的步...