如何减少C ++中以下代码的执行时间?

时间:2014-12-03 12:33:02

标签: c++ arrays sorting

我编写的代码执行时间为3.664秒,但时间限制为3秒。 问题是这个 -

N队参加火星联赛板球比赛,每场比赛 一对不同的球队完全相互比赛。因此,总共有 (N×(N1))/ 2匹配。专家为每个团队分配了力量, 一个正整数。奇怪的是,火星人群喜欢单独的比赛 从匹配中获得的广告收入是绝对值 两场比赛的优势之间的差异。鉴于 N队的优势,找到所有人获得的广告总收入 比赛。

输入格式

第1行:单个整数,N。

第2行:N个空格分隔整数,N队的优势。

#include<iostream>
using namespace std;

int main()
{
    int n;
    cin>>n;
    int stren[200000];
    for(int a=0;a<n;a++)
            cin>>stren[a];
    long long rev=0;
    for(int b=0;b<n;b++)
    {
            int pos=b;
            for(int c=pos;c<n;c++)
            {
                    if(stren[pos]>stren[c])
                        rev+=(long long)(stren[pos]-stren[c]);
                    else
                        rev+=(long long)(stren[c]-stren[pos]);
            }
    }
    cout<<rev;
}             

你能帮我解决一下吗?

5 个答案:

答案 0 :(得分:4)

代替if声明,请使用

rev += std::abs(stren[pos]-stren[c]);

abs返回两个整数之间的正差。这比if测试和随后的分支要快得多。 (long long)强制转换也是不必要的,尽管编译器可能会优化它。

您可以进行其他优化,但是应该这样做。如果您的abs功能在您的系统上实施得不好,那么可以始终使用此快速版本来计算i的绝对值:

(i + (i >> 31)) ^ (i >> 31)代表32位int

这根本没有分支,甚至会击败内联三元组! (但是你应该使用int32_t作为数据类型;如果你有64位int,那么你需要调整我的公式。)但我们在这里处于微优化领域。

答案 1 :(得分:4)

将循环重写为:

sort(stren);
for(int b=0;b<n;b++)
{
   rev += (2 * b - n + 1) * static_cast<long long>(stren[b]);
}

Live code here

为什么会起作用
你的循环会产生所有2对数字并将差值加到rev上。因此,在排序数组中,b th 项被减去(n-1-b)次并加上b次。因此,数字2 * b - n + 1


可能不需要1个微优化:

sort(stren);
for(int b = 0, m = 1 - n; b < n; b++, m += 2)
{
   rev += m * static_cast<long long>(stren[b]);
}

答案 2 :(得分:2)

for(int b = 0; b < n; b++)
{
    for(int c = b; c < n; c++)
    {
        rev += abs(stren[b]-stren[c]);
    }
}

这应该会让你加速,可能就够了。

答案 3 :(得分:1)

一种有趣的方法可能是从数组中剔除优势 - 如果该分布非常小。

所以:

std::unordered_map<int, int> strengths;
for (int i = 0; i < n; ++i) {
    int next;
    cin >> next;
    ++strengths[next];
}

这样,我们可以减少总和的数量:

long long rev = 0;
for (auto a = strengths.begin(); a != strengths.end(); ++a) {
    for (auto b = std::next(a), b != strengths.end(); ++b) {
        rev += abs(a->first - b->first) * (a->second * b->second);
        //     ^^^^ stren diff ^^^^^^^^   ^^ number of occurences ^^
    }
}
cout << rev;

如果强度往往会重复很多,这可以节省很多周期。

答案 4 :(得分:1)

我们在这个问题上究竟做了什么:对于元素对的所有组合,我们将这对元素之间的差异的绝对值相加。即考虑样本输入

3 10 3 5

Ans(仅取绝对值​​)=(3-10)+(3-3)+(3-5)+(10-3)+(10-5)+(3-5)= 7 + 0 + 2 + 7 + 5 + 2 = 23

注意我已修复3,遍历其余元素,找到差异并将它们添加到Ans,然后修复10,迭代通过剩余元素等等直到最后一个元素

不幸的是,上述程序需要N次(N-1)/ 2次迭代,这对时间限制来说是不合适的。

我们能改善吗?

让我们对数组进行排序并重复此过程。排序后,样品输入现在为3 3 5 10

让我们从修复最大元素10开始,然后像我们之前那样迭代数组(当然,时间复杂度是相同的)

Ans =(10-3)+(10-3)+(10-5)+(5-3)+(5-3)+(3-3)= 7 + 7 + 5 + 2 + 2 = 23

我们可以将上面的内容重新排列为

Ans =(10)(3) - (3 + 3 + 5)+ 5(2) - (3 + 3)+ 3(1) - (3)

注意一个模式?让我们概括一下。

假设我们有一个强度数组arr [N],大小为N,索引为0

Ans =(arr [N-1])(N-1) - (arr [0] + arr [1] + ... + arr [N-2])+(arr [N-2]) (N-2) - (arr [0] + arr [1] + arr [N-3])+(arr [N-3])(N-3) - (arr [0] + arr [1] + arr [N-4])+ ......等等

右。所以让我们把这个新想法付诸实践。我们将介绍一笔&#39;总和&#39;变量。一些基本的DP救援。

对于i = 0到N-1

sum = sum + arr [i]

Ans = Ans +(arr [i + 1] *(i + 1)-sum)

那就是它,你只需要对数组进行排序并只迭代一次。排除排序部分,它从N(N-1)/ 2下降到N次迭代,我想这被称为O(N)时间编辑:那就是整个O(N log N)时间< / p>

希望它有所帮助!