I'm trying to solve this exercise http://main.edu.pl/en/archive/amppz/2014/dzi and I have no idea how to improve perfomance of my code. Problems occure when program have to handle over 500,000 unique numbers(up to 2,000,000 as in description). Then it took 1-8s to loop over all this numbers. Tests I have used are from http://main.edu.pl/en/user.phtml?op=tests&c=52014&task=1263, and I testing it by command
program.exe < data.in > result.out
Description:
You are given a sequence of n integer a1, a2, ... an. You should determine the number of such ordered pairs(i, j), that i, j equeals(1, ..., n), i != j and ai is divisor of aj.
The first line of input contains one integer n(1 <= n <= 2000000)
The second line contains a sequence of n integers a1, a2, ..., an(1 <= ai <= 2000000).
In the first and only line of output should contain one integer, denoting the number of pairs sought.
For the input data:
5
2 4 5 2 6
the correct answer is: 6
Explanation: There are 6 pars: (1, 2) = 4/2, (1, 4) = 2/2, (1, 5) = 6/2, (4, 1) = 2/2, (4, 2) = 4/2, (4, 5) = 6/2.
For example:
- with 2M in total numbers and 635k unique numbers, there is 345mln iterations in total
- with 2M in total numbers and 2mln unqiue numbers, there is 1885mln iterations in total
#include <iostream>
#include <math.h>
#include <algorithm>
#include <time.h>
#define COUNT_SAME(count) (count - 1) * count
int main(int argc, char **argv) {
std::ios_base::sync_with_stdio(0);
int n; // Total numbers
scanf("%d", &n);
clock_t start, finish;
double duration;
int minVal = 2000000;
long long *countVect = new long long[2000001]; // 1-2,000,000; Here I'm counting duplicates
unsigned long long counter = 0;
unsigned long long operations = 0;
int tmp;
int duplicates = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &tmp);
if (countVect[tmp] > 0) { // Not best way, but works
++countVect[tmp];
++duplicates;
} else {
if (minVal > tmp)
minVal = tmp;
countVect[tmp] = 1;
}
}
start = clock();
int valueJ;
int sqrtValue, valueIJ;
int j;
for (int i = 2000000; i > 0; --i) {
if (countVect[i] > 0) { // Not all fields are setted up
if (countVect[i] > 1)
counter += COUNT_SAME(countVect[i]); // Sum same values
sqrtValue = sqrt(i);
for (j = minVal; j <= sqrtValue; ++j) {
if (i % j == 0) {
valueIJ = i / j;
if (valueIJ != i && countVect[valueIJ] > 0 && valueIJ > sqrtValue)
counter += countVect[i] * countVect[valueIJ];
if (i != j && countVect[j] > 0)
counter += countVect[i] * countVect[j];
}
++operations;
}
}
}
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("Loops time: %2.3f", duration);
std::cout << "s\n";
std::cout << "\n\nCounter: " << counter << "\n";
std::cout << "Total operations: " << operations;
std::cout << "\nDuplicates: " << duplicates << "/" << n;
return 0;
}
I know, I shouldn't sort the array at beginning, but I have no idea how to make it in better way.
Any tips will be great, thanks!
Here is improved algorithm - 2M unique numbers within 0.5s. Thanks to @PJTraill!
#include <iostream>
#include <math.h>
#include <algorithm>
#include <time.h>
#define COUNT_SAME(count) (count - 1) * count
int main(int argc, char **argv) {
std::ios_base::sync_with_stdio(0);
int n; // Total numbers
scanf("%d", &n);
clock_t start, finish;
double duration;
int maxVal = 0;
long long *countVect = new long long[2000001]; // 1-2,000,000; Here I'm counting duplicates
unsigned long long counter = 0;
unsigned long long operations = 0;
int tmp;
int duplicates = 0;
for (int i = 0; i < n; i++) {
scanf("%d", &tmp);
if (countVect[tmp] > 0) { // Not best way, but works
++countVect[tmp];
++duplicates;
} else {
if (maxVal < tmp)
maxVal = tmp;
countVect[tmp] = 1;
}
}
start = clock();
int j;
int jCounter = 1;
for (int i = 0; i <= maxVal; ++i) {
if (countVect[i] > 0) { // Not all fields are setted up
if (countVect[i] > 1)
counter += COUNT_SAME(countVect[i]); // Sum same values
j = i * ++jCounter;
while (j <= maxVal) {
if (countVect[j] > 0)
counter += countVect[i] * countVect[j];
j = i * ++jCounter;
++operations;
}
jCounter = 1;
}
}
finish = clock();
duration = (double)(finish - start) / CLOCKS_PER_SEC;
printf("Loops time: %2.3f", duration);
std::cout << "s\n";
std::cout << "\n\nCounter: " << counter << "\n";
std::cout << "Total operations: " << operations;
std::cout << "\nDuplicates: " << duplicates << "/" << n;
return 0;
}