J-建设道路

建设道路

http://www.nowcoder.com/questionTerminal/372e8f883a554bc48fab293552dea52c

分析

根据题意,我们可以得出是要求两两数字之间的差值的平方,由于数据很多,的暴力是肯定不行的。

那么我们只能写一个O(n)的算法,所以会想到求前缀和。

求解

这边由于都是差值,所以得进行一个转化,使得他成为前缀和的形式。

先排序,再两两做差即可。

int n;
scanf("%d",&n);
ll a[500010];
for (int i = 0;i < n;i ++) scanf("%lld",a + i); // 读入
sort(a,a + n); // 排序
n --; // 由于两两做差之后,数字个数就会减少1
for (int i = 0;i < n;i ++) {
    a[i] = a[i + 1] - a[i]; // 做差
}

接下来就可以进行找规律,从而写一个前缀和了。

找规律

假设有n = 5个数字,那么就有4个差,分别为:a,b,c,d。

那么两两做差就可以转化为连续和问题。

因此,题目所要求的过程即可转化为

因此,为了能够写出前缀和的形式,我们可以从左到右一个个数字来求和。

对于a,那么很简单只有
对于b,那么则有
对于c,那么则有
对于d,那么则有

那么规律便来了,很容易发现:每一项都是上一个式子平方和中加上自己这一项。

我们可以对每一个式子展开:
对于a的式子,我们可以得到:
对于b的式子,我们可以得到:
对于c的式子,我们可以得到:
。。。

这样就不难得到一个递推关系。
设每一个差是,项所对应的平方和是,额外需要求和的(也就是上述式子中)对应的是
那么便可以写出:(i从1开始,)


最后答案就是对的求和了。

代码

实际写的时候大可不必分别开数组,可以直接用变量优化掉:

ll s = 0;
ll last = 0;
ll l = 0;
for (int i = 0;i < n;i ++) {
    l = l + i + 1 * a[i] * a[i] + 2 * a[i] * last;
    s = s + l;
    last = last + (i + 1) * a[i];
}

最后根据题目意思,加上mod即可,注意这边得开long long,不然容易溢出。

//
//  header_useful.h
//  c++_acm
//
//  Created by Jack on 2019/7/23.
//  Copyright © 2019 Jack. All rights reserved.
//

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <vector>
#include <list>
#include <set>
#include <utility> // pair
#include <map>
#include <iostream>
#include <sstream>
#include <algorithm> // sort
#include <string>
#include <stack>
#include <queue>
#include <fstream>
#include <bitset>

using namespace std;

#define ll long long
#define uchar unsigned char
#define ushort unsigned short
#define uint unsigned int
#define ulong unsigned long
#define ull unsigned long long

#define INT_INF 0x7fffffff

#define pi acos(-1)

#define mx(a,b) (a) > (b) ? (a) : (b)
#define mn(a,b) (a) < (b) ? (a) : (b)
#define mem(a,b) memset(a,b,sizeof(a))
#define fre(a) freopen(a,"r",stdin)

#define cio ios::sync_with_stdio(false); // Do not use it before "scanf" and other c input!

#define itn int
#define nit int
#define inr int
#define mian main
#define ednl endl
#define fro for
#define fir for
#define reutrn return
#define retunr return
#define reutnr return

/* header_useful_h */

int main()
{
    int n;
    scanf("%d",&n);
    ll a[500010];
    for (int i = 0;i < n;i ++) scanf("%lld",a + i);
    sort(a,a + n);
    n --;
    for (int i = 0;i < n;i ++) {
        a[i] = a[i + 1] - a[i];
    }
    ll s = 0;
    ll last = 0;
    ll l = 0;
    const int mod = 1000000007;
    for (int i = 0;i < n;i ++) {
        l = (l + ((i + 1) * ((a[i] * a[i]) % mod) % mod + (2 * a[i] * last) % mod) % mod) % mod;
        s = (s + l) % mod;
        last = (last + ((i + 1) * a[i]) % mod) % mod;
    }
    printf("%lld\n",s);
    return 0;
}
全部评论

相关推荐

11-04 14:10
东南大学 Java
_可乐多加冰_:去市公司包卖卡的
点赞 评论 收藏
分享
2 收藏 评论
分享
牛客网
牛客企业服务