牛客多校第一場 F Sum of Maximum
阿新 • • 發佈:2018-07-22
i+1 -- main freopen pre map contest d+ 拉格朗日
題目鏈接
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; }
牛客多校第一場 F Sum of Maximum