[Codeforces 961G]Partitions

Description

題庫連接c++

給你 \(n\) 個不一樣的元素組成的集合 \(R\) ,每一個元素有一個權值 \(w\) 。對於一個子集集合 \(S\) ,它的價值爲 \(W(S)=|S|\cdot\sum\limits_{i\in S}w_i\) 。現要求將該集合 \(R\) 劃分紅 \(k\) 個互不相交的非空子集 \(S_i\) 。定義一種劃分的價值爲 \(\sum\limits_{i=1}^k W(S_i)\) 。求全部劃分的價值和。對大質數取模。ui

\(1\leq k\leq n\leq 2\cdot 10^5\)spa

Solution

容易發現對於不一樣的元素,他對答案的貢獻本質是相同的。即咱們只要求出某一種元素在全部方案中出現的次數 \(sum\) ,那麼答案就是 \(sum\times \sum\limits_{i=1}^n w_i\)code

考慮如何求 \(sum\)ip

容易發現它對 \(sum\) 的貢獻只與和它被劃分到同一集合的元素的個數有關。get

  1. 若是該元素被單獨劃分紅一組,那麼答案的貢獻爲 \(S(n-1, k-1)\) 。(其中形同 \(S(n, m)\) 的表示第二類斯特林數。)由於它單獨分爲一組,因此答案貢獻爲 \(1\) ,只要討論其餘 \(n-1\) 個元素怎麼分便可;
  2. 若是不是單獨分爲一組,咱們考慮用相似的方法來討論。仍是將其餘的 \(n-1\) 個元素先分好,共 \(S(n-1,k)\) 種。接下來考慮剩下的元素該如何放。對於一種劃分 \(n-1\) 個元素的狀況。咱們記每個子集元素個數爲 \(a_i\) 。那麼答案應該是 \(\sum\limits_{i=1}^k a_i+1\) 。不過由於 \(\sum\limits_{i=1}^k a_i=n-1\) ,因此在這種劃分狀況下,該元素的貢獻就是 \(n+k-1\) 。故總貢獻爲 \((n+k-1)\cdot S(n-1, k)\)

綜上答案就是 \((S(n-1,k-1)+(n+k-1)\cdot S(n-1, k))\cdot\sum\limits_{i=1}^n w_i\)it

\(S(n,m)\) 用通項公式計算就行了。io

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5, yzh = 1e9+7;

int x, n, k, inv[N+5];

int quick_pow(int a, int b) {
    int ans = 1;
    while (b) {
        if (b&1) ans = 1ll*ans*a%yzh;
        a = 1ll*a*a%yzh, b >>= 1; 
    }
    return ans;
}
int S(int n, int m) {
    int ans = 0;
    for (int i = 0; i <= m; i++) {
        int t = 1ll*inv[i]*inv[m-i]%yzh*quick_pow(m-i, n)%yzh;
        if (i&1) (ans -= t) %= yzh;
        else (ans += t) %= yzh;
    }
    return ans;
}
void work() {
    scanf("%d%d", &n, &k); inv[0] = inv[1] = 1;
    for (int i = 2; i <= k; i++) inv[i] = -1ll*yzh/i*inv[yzh%i]%yzh;
    for (int i = 1; i <= k; i++) inv[i] = 1ll*inv[i-1]*inv[i]%yzh;
    int sum = 0;
    for (int i = 1; i <= n; i++) scanf("%d", &x), (sum += x) %= yzh;
    int ans = (S(n-1, k-1)+1ll*(n+k-1)*S(n-1, k)%yzh)%yzh;
    ans = 1ll*ans*sum%yzh;
    printf("%d\n", (ans+yzh)%yzh);
}
int main() {work(); return 0; }
相關文章
相關標籤/搜索