我编写的代码执行时间为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;
}
你能帮我解决一下吗?
答案 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]);
}
为什么会起作用
你的循环会产生所有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>
希望它有所帮助!