牛客多校第一場 F. Sum of Maximum(拉格朗日插值)
阿新 • • 發佈:2019-01-10
題目描述
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都是可以提供貢獻的,所以這部分的貢獻為
再考慮a[i]~a[n]這一部分,因為此時要使x對結果產生貢獻,所以i~n的取值只能在[1,x]之間取,同時最少有一個數取到x這個值
根據容斥的原理,減掉選2個x的,加上選3個x的...所以這部分所產生的貢獻為
表示從最後的n-i+1個數中選出j個數的值為x,剩下的n-i+1-j個數再在[1,x]內任意取值
通過多項式展開式,這個式子可以轉化為
那麼通過x對最終答案的貢獻就為,那麼對於任意對答案的總貢獻為
最後的結果就為
其中可以藉助杜教的拉格朗日插值板子求出來(杜教太強辣,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; }