4kyu Smallest possible sum
题目背景:
Task
Given an array X of positive integers, its elements are to be transformed by running the following operation on them as many times as required:
if X[i] > X[j] then X[i] = X[i] - X[j]
When no more transformations are possible, return its sum (“smallest possible sum”).
Example
For instance, the successive transformation of the elements of input X = [6, 9, 21] is detailed below:
X_1 = [6, 9, 12] # -> X_1[2] = X[2] - X[1] = 21 - 9
X_2 = [6, 9, 6] # -> X_2[2] = X_1[2] - X_1[0] = 12 - 6
X_3 = [6, 3, 6] # -> X_3[1] = X_2[1] - X_2[0] = 9 - 6
X_4 = [6, 3, 3] # -> X_4[2] = X_3[2] - X_3[1] = 6 - 3
X_5 = [3, 3, 3] # -> X_5[1] = X_4[0] - X_4[1] = 6 - 3
题目分析:
本道题第一眼看下去就是很绕, 但是细细地思索下去会发现,既然我最终的目的是整个数组里面的每个值都是相等的,那么我可以每次只比较两个值,例如第一次比对 X[0] 和 X[1],连续套用这个算法形式,把两个值最后变成一样的,即 X’[0] = X’[1],再继续往后推进,比对 X’[1] 和 X[2],使得 X"[1] = X’[2],因为上一步中 X’[0] = X’[1],所以 X’[0] 肯定可以和 X’[1] 进行同等的变换,即满足 X"[0] = X"[1] = X’[2],大致思路就是不断地向数组尾部推进,直至推到数组尾部,题目解完,时间复杂度为 O(n)。同时需要注意到的是,题目存在一个trick,就是如果有一个元素是1的话,那么肯定数组最后会变为元素全为1的数组,考虑这一个因素进去后,可以进一步优化时间。
先附上比对两个值的算法:
unsigned long long step (unsigned long long tmp, unsigned long long start) {
while ( tmp != start ) {
if ( tmp > start ) {
if ( tmp % start == 0 ) return start;
tmp %= start;
}
else {
if ( start % tmp == 0 ) return tmp;
start %= tmp;
}
}
return tmp;
}
AC代码:
#include <vector>
unsigned long long step (unsigned long long tmp, unsigned long long start) {
while ( tmp != start ) {
if ( tmp > start ) {
if ( tmp % start == 0 ) return start;
tmp %= start;
}
else {
if ( start % tmp == 0 ) return tmp;
start %= tmp;
}
}
return tmp;
}
unsigned long long solution(const std::vector<unsigned long long>& arr){
if ( arr.size() == 1) return arr[0];
unsigned long long tmp;
unsigned long long start = arr[0];
for ( long long i = 1; i < arr.size(); i++ ) {
tmp = arr[i];
tmp = step(tmp, start);
if ( tmp == 1 ) return arr.size();
start = tmp;
}
return tmp * arr.size();
}