牛客网多校1 Sum of Maximum

题目:点击打开链接
题意:给出n个数,求

分析:

即数组最大值max * max为最大值的次数,求和,由于数字顺序不影响结果,所有可以先把数组从小到大排序。

a1,a2,a3, ... ,ai = x,aj = y, ... ,an

考虑到y时,mula = a1 * a2 * ... * ai

z = n - j + 1,表示y及后面还有z个数

max = x + 1,情况有mula * [(x + 1)^z - x^z],贡献度(x + 1) * mula * [(x + 1)^z - x^z]

mula表示前面i个数可以在[1,a[k]] (1<=k<=i) 中任意取。

(x+1)^z表示后面z个数可以在[1,a[k]] (j<=k<=n)中任意取,

-x^z表示要减去后面z个数都在[1,x]中任意取的情况,即此时没有数达到x + 1,最大值不为x +1。

max = x + 2,情况有mula * [(x + 2)^z - (x + 1)^z],贡献度(x + 2) * mula * [(x + 2)^z - (x + 1)^z]

...

max = y,情况有mula * [y^z - (y - 1)^z],贡献度y * mula * [y^z - (y - 1)^z]

将贡献度求和

当x < =y时,可以化简为

mula * {y^(z+1) - x^(z+1) - f(y-1,z) + f(x-1,z)}   //f(n,z) = 1^z + 2^z + 3^z + ... + n^z

p次方前n项和f(n,z) = 1^z + 2^z + 3^z + ... + n^z

可以用拉格朗日插值法或者伯努利数来做,赛后用伯努利数(复杂度为n^2)过了。其他人拉格朗日插值法都是用的杜教的板子,我看不懂。于是自己写了下,一直TLE,复杂度为n^2*logn,不知道怎么优化了,欢迎各位大佬提点。

伯努利数AC代码:

#pragma comment(linker, "/STACK:102400000,102400000")///手动扩栈
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cassert>
#include<string>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
using namespace std;
#define debug test
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#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--)
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
#define eps 1e-10
#define PI acos(-1.0)
typedef pair<int,int> PII;
const ll mod = 1e9+7;
const int N = 1e3+10;

ll gcd(ll p,ll q){return q==0?p:gcd(q,p%q);}
ll qp(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;}
int to[4][2]={{-1,0},{1,0},{0,-1},{0,1}};

int b[N],c[N][N],inv[N],ans,tmp;
ll calc(ll n,int k){///求和:1^k+2^k+3^k+4^k+....+n^k
    n++;n%=mod;tmp=n;
    ans=0;
    for(int i=1;i<=k+1;i++){
        ans=(ans+(ll)c[k+1][i]*b[k+1-i]%mod*n%mod)%mod;
        n=(ll)n*tmp % mod;
    }
    ans=(ll)ans*inv[k+1] % mod;
    return ans;
}

void calc_init(){
    c[0][0]=1;
    for (int i=1;i<N;i++){
        for (int j=1;j<=i;j++)
            c[i][j]=(c[i-1][j-1]+c[i-1][j])%mod;
        c[i][0]=1;
    }
    inv[1]=1;
    for(int i=2;i<N;i++) inv[i]=(ll)inv[mod%i]*(mod-mod/i)%mod;
    b[0]=1;
    for(int i=1;i<N;i++){
        b[i]=0;
        for(int k=0;k<i;k++)
            b[i]=(b[i]+(ll)c[i+1][k]*b[k]%mod)%mod;
        b[i]=((ll)b[i]*(-inv[i+1]) % mod+mod)%mod;
    }
}

ll n,k;

int main() {
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    calc_init();
    while(cin>>n>>k) cout<<calc(n,k)<<endl;
    return 0;
}

拉格朗日插值法TLE代码:

#pragma comment(linker, "/STACK:102400000,102400000")///手动扩栈
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cstdio>
#include<bitset>
#include<vector>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<deque>
#include<list>
#include<set>
#include<map>
using namespace std;
#define debug test
#define mst(ss,b) memset((ss),(b),sizeof(ss))
#define ll long long
#define ull unsigned long long
#define pb push_back
#define mp make_pair
#define inf 0x3f3f3f3f
#define eps 1e-10
#define MOD 1000000007
#define PI acos(-1.0)
const int N = 1e6+10;

ll gcd(ll p,ll q)
{
    return q==0?p:gcd(q,p%q);
}
int to[4][2]= {{-1,0},{1,0},{0,-1},{0,1}};

ll m,a[N],sum,fac[N],y[N];

ll qp(ll a,ll b){
    ll s=1;
    while(b){
        if(b&1) s=s*a%MOD;
        a=a*a%MOD,b>>=1;
    }
    return s;
}

void init() {
    for(int i=2; i<N; i++) fac[i]=fac[i-1]*i%MOD; ///预处理阶乘
}

ll sv(ll n,ll k){
    ll ans=0;
    fac[0]=fac[1]=1,y[1]=1;
    for(int i=2; i<=k+2; i++) y[i]=(y[i-1]+qp(i,k))%MOD; ///预处理求出每一项的结果
    if(n<=k+2)  return y[n];
    ll sum=1,sig;
    for(ll i=n-k-2; i<=n-1; i++) sum=sum*i%MOD;
    for(ll i=1; i<=k+2; i++) ///k+1项的多项式有k+2项
    {
        ll fz=sum*qp(n-i,MOD-2)%MOD;///分子
        ll fm=qp(fac[i-1]*fac[k+2-i]%MOD,MOD-2);///分母
        if((k+2-i)%2==0) sig=1;///正负号
        else sig=-1;
        ans=(ans+sig*y[i]*fz%MOD*fm%MOD+MOD)%MOD;
        ///ans+= sig*y[i]*fz%MOD*fm%MOD;
    }
    return (ans%MOD+MOD)%MOD;
}

int main(){
    ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
    init();
    while(cin>>m){
        sum=0;
        for(int i=1; i<=m; i++) cin>>a[i];
        sort(a+1,a+m+1);
        ll now=1;
        for(int i=1; i<=m; i++){
            if(a[i]==a[i-1]){
                (now*=a[i])%=MOD;
                continue;
            }
            ll s1=(qp(a[i],m-i+2)-sv(a[i]-1,m-i+1)+MOD)%MOD;
            ll s2=(qp(a[i-1],m-i+2)-sv(a[i-1]-1,m-i+1)+MOD)%MOD;
            sum += ( now*(s1-s2+MOD)%MOD)%MOD;
            (now*=a[i])%=MOD;
        }
        cout<<(sum%MOD+MOD)%MOD<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/tianwei0822/article/details/81232606