现在的位置: 首页 > 综合 > 正文

clang一月月赛P1021,简单的转化由n^2->n.

2018年04月28日 ⁄ 综合 ⁄ 共 947字 ⁄ 字号 评论关闭
题目描述

数轴上有N个点,任意两点连线得到n(n-1)条线段,试求线段的总长。

输入

第一行,一个整数N,表示点数。 接下来N行,每行一个整数X_i,表示点的坐标。

输出

一个整数,表示线段的总长。

样例输入
5 1 5 3 2 4
样例输出
40
提示

N  < =  10000  ,  0  < =  X_i  < =  1000000000

从X_i看出来,他的数据应该为10^9,所以一定要考虑long long,用上long long后,期初的想法就是扫一遍,然后O(n2)就能结果,当时担心着T,但是没有T,

过了后,又想到了另外一种简单的O(n)算法、先写出来O(n2)的方法了:

# include<cstdio>
# include<iostream>
# include<algorithm>

using namespace std;

# define MAX 10000+5

long long  a[MAX];

int main(void)
{
    int n;
    while ( cin>>n )
    {
        for ( int i = 0;i < n;i++ )
        {
            cin>>a[i];
        }
        sort(a,a+n);
        long long  sum = 0;
        for ( int i = 0;i < n-1;i++ )
        {
            for ( int j = i+1;j < n;j++ )
            {
                sum+=a[j]-a[i];
            }
        }
        cout<<2*sum<<endl;


    }


    return 0;
}

O(n)的算法思想就是算排完序后的点对于答案的贡献程度了,并且发现了,第一个点与后面的点的连线对于答案的贡献恰好满足前缀和:

# include<cstdio>
# include<iostream>
# include<algorithm>

using namespace std;

# define MAX 10000+5

long long  a[MAX];
long long sa[MAX];

int main(void)
{
    int n;
    while ( cin>>n )
    {
        for ( int i = 1;i <= n;i++ )
        {
            cin>>a[i];
        }
        sort(a+1,a+1+n);
        for ( int i = 1;i <= n;i++ )
        {
            sa[i] = sa[i-1]+a[i];
        }
        long long sum = 0;
        for ( int i = 1;i <= n;i++ )
        {
            sum+=sa[n]-sa[i-1]-a[i]*(n+1-i);
        }
        cout<<sum*2<<endl;
    }


    return 0;
}

抱歉!评论已关闭.