牛客多校第一场 F Sum of Maximum

题目链接

https://www.nowcoder.com/acm/contest/139/F

分析

枚举i从1到a[i]的最大值,每个段考虑i的贡献。
关键在于要在O(n)或者O(nlogn)时间内求出一个最高次为n次的多项式在x(x<=1e9)处的值来,可以利用拉格朗日差值。
首先求出将要计算的函数在x=1,2,3.....m+1(最高次为m次)处的函数值,然后用拉格朗日差值的公式就可以求出在任意一点处函数值

代码

#include <iostream>
#include <cmath>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <map>
#include <ctime>
using namespace std;
typedef long long ll;
const ll MOD=1e9+7;
const int maxn=100050;
int a[maxn];
ll x[maxn];
ll y[maxn];
ll inv[maxn];
ll Pow(ll x,ll n) {
    ll ans=1,base=x%MOD;
    if(base<0) base+=MOD;
    while(n) {
        if(n&1) ans=ans*base%MOD;
        base=base*base%MOD;
        n>>=1;
    }
    return ans;
}
void init() {
    ll f=1;
    for(int i = 1; i < maxn; ++i) f=f*i%MOD;
    inv[maxn-1]=Pow(f,MOD-2);
    for(int i = maxn-2; i >= 0; --i) {
        inv[i]=inv[i+1]*(i+1)%MOD;
    }
}
ll lagrange(ll p,int m) {
    if(p<=m) return y[p];
    ll tot=1;
    ll ans=0;
    ll pre[m+2],suf[m+2];
    pre[0]=suf[m+1]=1;
    for(int i = 1; i <= m; ++i){
        pre[i]=pre[i-1]*(p-x[i])%MOD;
        suf[m-i+1]=suf[m-i+2]*(p-x[m-i+1])%MOD;
    }
    for(int i = 1; i <= m; ++i) {
        ll t=pre[i-1]*suf[i+1]%MOD;
        t=t*inv[i-1]%MOD*inv[m-i]%MOD;
        t=t*y[i]%MOD;
        if((m-i)&1) t=-t;
        ans+=t;
    }
    ans%=MOD;
    if(ans<0) ans+=MOD;
    return ans;
}
int main() {
    //freopen("in.txt","r",stdin);
    int n;
    init();
    while(scanf("%d", &n)!=EOF){
        for(int i = 1; i <= n; ++i) scanf("%d", a+i);
        sort(a+1,a+n+1);
        a[0]=0;
        ll pro=1,ans=0;
        for(int i = 1; i <= n; ++i) {
            int m=n+4-i;
            for(int j = 1; j <= m; ++j) {
                x[j]=j;
                y[j]=(Pow(x[j],n-i+1)-Pow(x[j]-1,n-i+1))%MOD;
                y[j]=y[j]*x[j]%MOD;
                if(y[j]<0) y[j]+=MOD;
            }
            for(int j = 1; j <= m; ++j) {
                y[j]=(y[j]+y[j-1])%MOD;
            }
            ll t=lagrange(a[i],m)-lagrange(a[i-1],m);
            t%=MOD;
            ans=(ans+pro*t%MOD);
            pro=pro*a[i]%MOD;
        }
        ans=(ans%MOD+MOD)%MOD;
        printf("%lld\n", ans);
    }
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/sciorz/p/9348352.html