zoukankan      html  css  js  c++  java
  • CF 961G Partitions

    推不动式子

    我们考虑每一个$w_i$对答案的贡献,因为题目中定义集合的价值为$W(S) = left | S ight |sum_{x in S}w_x$,这个系数$left | S ight |$可以看作集合中所有的元素(包括$i$自己)对$i$产生了一次贡献,那么我们考虑一个元素$j$对$i$的贡献:

    1、$j == i$的时候,相当于求把$n$个小球放到$k$个盒子里面的方案数,为$S(n, k)$($S$表示第二类斯特林数)。

    2、$j eq i$的时候,只有$j$和$i$放在同一个集合里面才能产生贡献,为$S(n - 1, k)$。

    然后代入第二类斯特林数的通项公式直接算就好了。

    最后的答案就是

    $$(S(n, k) + (n - 1)S(n - 1, k)) * sum_{i = 1}^{n}w_i$$

    时间复杂度$O(klogk)$。

    另外一种高能的推法:传送门

    Code:

    #include <cstdio>
    #include <cstring>
    using namespace std;
    typedef long long ll;
    
    const int N = 2e5 + 5;
    const ll P = 1e9 + 7;
    
    ll sum = 0, fac[N], inv[N];
    
    inline ll fpow(ll x, ll y) {
        ll res = 1LL;
        for (; y > 0; y >>= 1) {
            if (y & 1) res = res * x % P;
            x = x * x % P;
        }
        return res;
    }
    
    inline ll getS(int n, int k) {
        ll res = 0;
        for (int i = 0; i <= k; i++) {
            ll opt = i & 1 ? -1LL : 1LL;
            res = (res + opt * inv[i] % P * fpow(k - i, n) % P * inv[k - i] % P + P) % P;
        }
        return res;
    }
    
    int main() {
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++) {
            ll now; scanf("%lld", &now);
            sum = (sum + now) % P;
        }
        
        fac[0] = 1;
        for (int i = 1; i <= n; i++) fac[i] = fac[i - 1] * i % P;
        inv[n] = fpow(fac[n], P - 2);
        for (int i = n - 1; i >= 0; i--) inv[i] = inv[i + 1] * (i + 1) % P;
        
        ll ans = (getS(n, k) + (n - 1) * getS(n - 1, k) % P) % P;
        ans = ans * sum % P;
        printf("%lld
    ", ans);
        
        return 0;
    }
    View Code
  • 相关阅读:
    交易之道
    走出幻觉,走向成熟(阅读心得一)
    爱由心生
    正则资料整理(转载)
    需要学习的.NET技术(转载)
    抽象类与接口的区别
    心存感激
    MYSQL 远程访问被限制
    PHP积累
    Git积累
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/10204511.html
Copyright © 2011-2022 走看看