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;
}
原文:https://www.cnblogs.com/sciorz/p/9348352.html