CodeJam 最小标量产品问题
Posted
技术标签:
【中文标题】CodeJam 最小标量产品问题【英文标题】:CodeJam Minimum Scalar Product Issue 【发布时间】:2016-05-21 23:46:56 【问题描述】:我在练习这个问题,很快就找到了正确的算法,但是在实现它时,我遇到了一些奇怪的事情。起初,我意识到我被整数类型的溢出所困扰,所以开始使用 __int64。那是我注意到下一个奇怪的事情的时候。所以首先,这是我的代码...
#include <cstdlib>
#include <iostream>
#include <fstream>
#include <vector>
#include <algorithm>
#include <numeric>
using namespace std;
const string cInputFileName = "E:\\CodeJamInputs\\d-large-practice.in";
const string cOutputFileName = "E:\\CodeJamInputs\\d-large-practice.out.txt";
__int64 FindSmallestProductOfSums(const vector<int> &iVec1, const vector<int> &iVec2)
vector<int> v1 = iVec1;
vector<int> v2 = iVec2;
sort(v1.begin(), v1.end());
sort(v2.begin(), v2.end(), greater<int>());
__int64 productOfSumsA = inner_product(v1.begin(), v1.end(), v2.begin(), 0);
__int64 productOfSumsB = 0;
for(vector<int>::size_type i = 0; i < v1.size(); ++i)
productOfSumsB += (__int64)v1[i] * (__int64)v2[i];
return productOfSumsB;
int _tmain(int argc, _TCHAR* argv[])
ifstream inputFile(cInputFileName, ifstream::in);
ofstream outputFile(cOutputFileName, ofstream::out);
if(inputFile.is_open() && outputFile.is_open())
int numCases;
inputFile >> numCases;
for(int i = 0; i < numCases; ++i)
int vectorSizes;
inputFile >> vectorSizes;
vector<int> vec1, vec2;
for(int j = 0; j < vectorSizes; ++j)
int value;
inputFile >> value;
vec1.push_back(value);
for(int j = 0; j < vectorSizes; ++j)
int value;
inputFile >> value;
vec2.push_back(value);
__int64 smallestProductOfSums = FindSmallestProductOfSums(vec1, vec2);
outputFile << "Case #" << (i + 1) << ": " << smallestProductOfSums;
outputFile << endl;
inputFile.close();
outputFile.close();
所以,如您所见,我对两个向量进行了两次计算。一种使用 STL inner_product,另一种只是手动迭代。那么愚蠢的是,对于问题中的大数据集,inner_product 方法导致错误的返回,而手动的方法是正确的。进入 STL 代码,在我看来确实发生了溢出,因为 Ty Val 变量似乎是一个 int,这当然是结果被累积的地方。
那么,我想知道的是,对于那些使用 inner_product 解决了这个问题的人,你认为区别是什么?我尝试将 0LL 作为初始参数传递给咯咯笑,实际上,它确实导致了不同的答案,但仍然不是正确的答案。奇怪的是,在我添加显式 __int64 强制转换之前,它确实得到了与手动方法相同的答案。所以这里肯定有一些奇怪的类型和溢出,只是不确定是什么。无论如何,对于小型和大型系列,我都得到了正确的答案,但我只是看到有些人使用了 inner_product,我无法让它发挥作用。让我重新表述一下...inner_product 适用于小型数据集,但不适用于大型数据集,因为我的手动解决方案适用于小型和大型数据集。
以下是问题中每个案例的输出(大型数据集总共 10 个)。对于每种情况,都有三个输出。第一个是使用手动计算的方法(正确答案),第二个是使用 init_product 的 init 为“0”(错误答案),第三个是使用 inner_product 的 init 为“0LL”(错误答案)。另外,凭直觉,我也编译为 x64 目标,但结果是一样的。
案例#1:-7839202227936 案例#1:-886912736 案例#1:-1104693507808
案例#2:7999201712083 案例二:1972606931 案例二:1127254038483
案例#3:-1313429236847 案例#3:830755729 案例#3:-175262903407
案例#4:-3710387739618 案例#4:464004126 案例#4:-89730309090
案例#5:-3414920765916 案例#5:-421765596 案例#5:-82026144220
案例#6:-1271937742993 案例#6:-627423377 案例#6:-30692194449
案例 #7:-1964394407029 案例#7:-1594352757 案例 #7:-40249058421
案例#8:-1884282427866 案例#8:1208215078 案例#8:-101871000026
案例 #9:-4044533757860 案例#9:1325434972 案例#9:-106048747428
案例 #10:-838783451371 案例 #10:-1264828651 案例 #10:-44214501611
抱歉,这篇文章很长,但我认为这是一个有趣的问题。
【问题讨论】:
【参考方案1】:CPP reference 包含 inner_product 的示例实现,如下所示:
...
value = value + *first1 * *first2;
...
inner_product涉及两种类型:
-
累加器的类型(从传入的初始值推导出来,例如0LL)
被相乘的元素的类型(从数组的类型推导出来)
因此,在您的情况下,累加器有一个 int64,但元素只有 int(可能是 32 位数据类型)。当乘法发生时,乘法的结果以 32 位精度计算!
因此,有两个可能的溢出位置,一个在 + 中,一个在 * 中。更改初始值会修复累加器,但您仍然面临乘法溢出的风险。
解决此问题的最简单方法是将输入数组更改为 int64 数组而不是 int。在这种情况下,乘法将以 64 位精度完成。
【讨论】:
以上是关于CodeJam 最小标量产品问题的主要内容,如果未能解决你的问题,请参考以下文章
CodeJam Qualification Round 2022
CodeJam Qualification Round 2022
CodeJam Qualification Round 2022