牛客网暑期ACM多校训练营(第一场)F——Sum of Maximum

题意:

给你n个数,求

a[i]<=1e9, n<=1000


题解:

考虑算每个数最大的时候的贡献,即这个数*这个数最大时的方案数。

先按a[i]从小到大排序。

对于每个a[i], 里面包含了a[i] - a[i-1] 个值。对于每个值x,方案数即为 所有数最多为x时的方案数减去所有数最多为x-1时的方案数。

最后推出来需要求一下幂和,即1^k+2^k+...n^k。这个可以用伯努利数也可以用拉格朗日插值。

伯努利数预处理时的复杂度为k^2, 查询1^k+2^k+...n^k时的复杂度为k.

代码:

#include<bits/stdc++.h>
#define For(G,x) for(int h=G.head[x],o=G.V[h]; h; o=G.V[h=G.to[h]])
#define fir first
#define sec second
#define pii pair<int,int>
#define debug(x) cout<<#x<<" = "<<x<<endl;
using namespace std;
const int MAXN = 1e5 + 5;
const int MOD = 1e9 + 7;
#define ll long long

ll inv[MAXN],fac[MAXN],invf[MAXN],B[MAXN];
int a[MAXN];
inline ll C(ll x,ll y) {
    return fac[x] * invf[y] % MOD * invf[x-y] % MOD;
}
 
 
ll pow_(ll x,ll y) {
    x %= MOD;
    ll r=1;
    while(y) {
        if(y & 1) r = r * x % MOD;
        x = x * x % MOD;
        y >>= 1;
    }
    return r;
}

//预处理伯努利数
void init(){
    invf[0] = inv[0] = inv[1] = fac[0] = fac[1] = 1;
    for(ll i=1; i<=2005; i++) fac[i] = fac[i-1]* i % MOD;
    for(int i=2; i<=2005; i++) inv[i] = (MOD-MOD/i) * inv[MOD%i] % MOD;
    for(int i=1; i<=2005; i++) invf[i] = invf[i-1] * inv[i] % MOD;
    B[0] = 1;
    for(int i=1; i<=2001; i++) {
        B[i]=0;
        for(int j=0; j<i; j++) B[i] = (B[i] + C(i+1,j) * B[j]) % MOD;
        B[i]=((B[i] * -inv[i+1]) % MOD + MOD)%MOD;
    }
}

//求1^k+2^k+...n^k
ll getv(int n, int k) {
    ll Ans=0;
    for(int i=1; i <= k+1; i++) Ans=(Ans + C(k+1,i) * B[k+1-i] % MOD *pow_(n+1,i)) % MOD;
    Ans = Ans * inv[k+1] % MOD;
    return Ans;
}
 

int main() {
#ifdef LOCAL
    freopen("input.txt", "r", stdin);
#endif
    int n;
    init();
    while(~scanf("%d", &n)) {
        ll ans = 0;
        int pre = 0;
        ll base = 1, ext = 0;
 
        for(int i = 1; i <= n; i++) scanf("%d", &a[i]);
        sort(a + 1, a + 1 + n);
        for(int i = 1; i <= n; i++) {
            if(a[i] == a[i - 1]) continue;
            ll t = (a[i] * pow_(a[i], n - i + 1) - (getv(a[i] - 1, n - i + 1)
            - getv(pre, n - i + 1)) + MOD) % MOD * base % MOD;
            t = (t - (pre + 1) * ext % MOD + MOD) % MOD;
            ans = (ans + t) % MOD;
            ext = pow_(a[i], n - i + 1) * base % MOD;
            base = base * a[i] % MOD;
            pre = a[i];
        }
        printf("%lld\n", ans);
    }
 
}

猜你喜欢

转载自blog.csdn.net/c6376315qqso/article/details/81131323