1. 程式人生 > >牛客多校第一場 F. Sum of Maximum(拉格朗日插值)

牛客多校第一場 F. Sum of Maximum(拉格朗日插值)

題目描述

Given a1, a2, ..., an, find 

modulo (109+7).

輸入描述:

The input consists of several test cases and is terminated by end-of-file.
The first line of each test case contains an integer n.
The second line contains n integers a1, a2, ..., an.

輸出描述:

For each test case, print an integer which denotes the result.

示例1

輸入

複製

2
1 2
5
2 3 3 3 3
​

輸出

複製

3
453

備註:

* 1 ≤ n ≤ 1000
* 1 ≤ ai ≤ 109
* The number of test cases does not exceed 10.

題目大意:就是按題目所給的式子求出最後的值,答案對1e9+7取模

題目思路:由於每個數a[i]的順序對最後的結果沒有影響,所以我們可以先把陣列按照數從小到大排序。

接下來對於最大值x\in [a[i-1],a[i]] 對最終的答案的貢獻,對於所有的a_{j}(j<i-1)),

x都是可以提供貢獻的,所以這部分的貢獻為res=\prod_{j=1}^{i-1}a[j]

再考慮a[i]~a[n]這一部分,因為此時要使x對結果產生貢獻,所以i~n的取值只能在[1,x]之間取,同時最少有一個數取到x這個值

根據容斥的原理,減掉選2個x的,加上選3個x的...所以這部分所產生的貢獻為

\sum_{j=1}^{n-i+1}C_{n-i+1}^{j}*(-1)^{j-1}*x^{n-i+1-j}

表示從最後的n-i+1個數中選出j個數的值為x,剩下的n-i+1-j個數再在[1,x]內任意取值

通過多項式展開式,這個式子可以轉化為      f(x)=x^{n-i+1}-(x-1)^{n-i+1}

那麼通過x對最終答案的貢獻就為x*res*f(x),那麼對於任意x\in [a[i-1],a[i]]對答案的總貢獻為

sum_{i}=res*\sum_{x=a[i-1]}^{a[i]}x*(x^{n-i+1}-(x-1)^{n-i+1})

最後的結果就為ans=\sum_{i=1}^{n}sum_{i}

其中\sum_{x=a_{i-1}}^{a_{i}} x*x^{n-i+1}-(x-1)^{n-i+1}可以藉助杜教的拉格朗日插值板子求出來(杜教太強辣,orz

#include <bits/stdc++.h>
#define fi first
#define se second
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pb push_back
#define MP make_pair
#define FIN freopen("in.txt","r",stdin)
#define fuck(x) cout<<"["<<x<<"]"<<endl
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int>pii;
const int MX=1000+7;
const ll mod=1e9+7;

namespace polysum {
    #define rep(i,a,n) for (int i=a;i<n;i++)
    #define per(i,a,n) for (int i=n-1;i>=a;i--)
    const int D=2010;
    ll a[D],f[D],g[D],p[D],p1[D],p2[D],b[D],h[D][2],C[D];
    ll powmod(ll a,ll b){ll res=1;a%=mod;assert(b>=0);for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
    ll calcn(int d,ll *a,ll n) { // a[0].. a[d]  a[n] 
        if (n<=d) return a[n];
        p1[0]=p2[0]=1;
        rep(i,0,d+1) {
            ll t=(n-i+mod)%mod;
            p1[i+1]=p1[i]*t%mod;
        }
        rep(i,0,d+1) {
            ll t=(n-d+i+mod)%mod;
            p2[i+1]=p2[i]*t%mod;
        }
        ll ans=0;
        rep(i,0,d+1) {
            ll t=g[i]*g[d-i]%mod*p1[i]%mod*p2[d-i]%mod*a[i]%mod;
            if ((d-i)&1) ans=(ans-t+mod)%mod;
            else ans=(ans+t)%mod;
        }
        return ans;
    }
    void init(int M) {
        f[0]=f[1]=g[0]=g[1]=1;
        rep(i,2,M+5) f[i]=f[i-1]*i%mod;
        g[M+4]=powmod(f[M+4],mod-2);
        per(i,1,M+4) g[i]=g[i+1]*(i+1)%mod;
    }
    ll polysum(ll m,ll *a,ll n) { // a[0].. a[m] \sum_{i=0}^{n-1} a[i]
        ll b[D];
        for(int i=0;i<=m;i++) b[i]=a[i];
        b[m+1]=calcn(m,b,m+1);
        rep(i,1,m+2) b[i]=(b[i-1]+b[i])%mod;
        return calcn(m+1,b,n-1);
    }
    ll qpolysum(ll R,ll n,ll *a,ll m) { // a[0].. a[m] \sum_{i=0}^{n-1} a[i]*R^i
        if (R==1) return polysum(n,a,m);
        a[m+1]=calcn(m,a,m+1);
        ll r=powmod(R,mod-2),p3=0,p4=0,c,ans;
        h[0][0]=0;h[0][1]=1;
        rep(i,1,m+2) {
            h[i][0]=(h[i-1][0]+a[i-1])*r%mod;
            h[i][1]=h[i-1][1]*r%mod;
        }
        rep(i,0,m+2) {
            ll t=g[i]*g[m+1-i]%mod;
            if (i&1) p3=((p3-h[i][0]*t)%mod+mod)%mod,p4=((p4-h[i][1]*t)%mod+mod)%mod;
            else p3=(p3+h[i][0]*t)%mod,p4=(p4+h[i][1]*t)%mod;
        }
        c=powmod(p4,mod-2)*(mod-p3)%mod;
        rep(i,0,m+2) h[i][0]=(h[i][0]+h[i][1]*c)%mod;
        rep(i,0,m+2) C[i]=h[i][0];
        ans=(calcn(m,C,n)*powmod(R,n)-c)%mod;
        if (ans<0) ans+=mod;
        return ans;
    }
}

int n;
ll a[MX],b[MX][MX],ans,tmp;

void init(){
    for(int i=1;i<=n;i++){
        for(int j=1;j<=n-i+1;j++)
            b[i][j]=(j*(polysum::powmod(j,n-i+1)-polysum::powmod(j-1,n-i+1))%mod+mod)%mod;
    }
}

int main(){
    polysum::init(MX);
    
    while(~scanf("%d",&n)){
        init();
        ans=0;tmp=1;
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        sort(a+1,a+n+1);
        for(int i=1;i<=n;i++){
            if(a[i]==a[i-1]) continue;
            ans=(ans+tmp*(polysum::polysum(n-i+1,b[i],a[i]+1)-polysum::polysum(n-i+1,b[i],a[i-1]+1))%mod+mod)%mod;
            tmp=(tmp*a[i])%mod;
        }
        printf("%lld\n",(ans+mod)%mod);
    }
    return 0;
}