牛客多校第一场 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
", ans);
	}
	return 0;
}

原文地址:https://www.cnblogs.com/sciorz/p/9348352.html