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;
}
I expect the following to work a lot faster than the OP’s algorithm (optimisations oblique):
(The type of values and frequencies should be 32-bit unsigned, counts 64-bit – promote before calculating a count, if your language would not.)
Read the number of values, N.
Read each value v, adding one to its frequency freq[v] (no need to store it).
(freq[MAX] (or MAX+1) can be statically allocated for probably optimal initialisation to all 0)
Calculate the number of pairs involving 1 from freq[1] and the number of values.
For every i in 2..MAX (with freq[i] > 0):
Calculate the number of pairs (i,i) from freq[i].
For every multiple m of i in 2m..MAX:
(Use m as the loop counter and increment it, rather than multiplying)
Calculate the number of pairs (i,m) from freq[i] and freq[m].
(if freq[i] = 1, one can omit the (i,i) calculation and perform a variant of the loop optimised for freq[i] = 1)
(One can perform the previous (outer) loop from 2..MAX/2, and then from MAX/2+1..MAX omitting the processing of multiples)
The number of pairs (i,i) = freq[i]C2 = ( freq[i] * (freq[i] - 1) ) / 2 .
The number of pairs (i,j) = freq[i] * freq[j] for i ≠ j.
This avoids sorting, sqrt and division.
Other optimisations
One can store the distinct values, and scan that array instead (the order does not matter); the gain or loss due to this depends on the density of the values in 1..MAX.
If the maximum frequency is < 216, which sounds very probable, all products will fit in 32 bits. One could take advantage of this by writing functions with the numeric type as a template, tracking the maximum frequency and then choosing the appropriate instance of the template for the rest. This costs N*(compare+branch) and may gain by performing D2 multiplications with 32 bits instead of 64, where D is the number of distinct values. I see no easy way to deduce that 32 bits suffice for the total, apart from N < 216.
If parallelising this for n processors, one could let different processors process different residues modulo n.
I considered keeping track of the number of even values, to avoid a scan of half the frequencies, but I think that for most datasets within the given parameters that would yield little advantage.
Ok, I am not going to write your whole algorithm for you, but it can definitely be done faster. So i guess this is what you need to get going:
So you have your list sorted, so there are a lot of assumptions you can make from this. Take for instance the highest value. It wont have any multiples. The highest value that does, will highest value divided by two.
There is also one other very usefull fact here. A multiple of a multiple is also a multiple. (Still following? ;)). Take for instance the list [2 4 12]. Now you've found (4,12) as a multiple pair. If you now also find (2,4), then you can deduce that 12 is also a multiple of 2.
And since you only have to count the pairs, you can just keep a count for each number how many multiples it has, and add that when you see that number as a multiple itself.
This means that it is probably best to iterate your sorted list backwards, and look for divisors instead.
And maybe store it in some way that goes like
[ (three 2's ), (two 5's), ...]
ie. store how often a number occurs. Once again, you don't have to keep track of it's id, since you only need to give them the total number of pairs.
Storing your list this way helps you, because all the 2's are going to have the same amount of multiples. So calculate once and then multiply.
Related
Given a number 1 <= N <= 3*10^5, count all subsets in the set {1, 2, ..., N-1} that sum up to N. This is essentially a modified version of the subset sum problem, but with a modification that the sum and number of elements are the same, and that the set/array increases linearly by 1 to N-1.
I think i have solved this using dp ordered map and inclusion/exclusion recursive algorithm, but due to the time and space complexity i can't compute more than 10000 elements.
#include <iostream>
#include <chrono>
#include <map>
#include "bigint.h"
using namespace std;
//2d hashmap to store values from recursion; keys- i & sum; value- count
map<pair<int, int>, bigint> hmap;
bigint counter(int n, int i, int sum){
//end case
if(i == 0){
if(sum == 0){
return 1;
}
return 0;
}
//alternative end case if its sum is zero before it has finished iterating through all of the possible combinations
if(sum == 0){
return 1;
}
//case if the result of the recursion is already in the hashmap
if(hmap.find(make_pair(i, sum)) != hmap.end()){
return hmap[make_pair(i, sum)];
}
//only proceed further recursion if resulting sum wouldnt be negative
if(sum - i < 0){
//optimization that skips unecessary recursive branches
return hmap[make_pair(i, sum)] = counter(n, sum, sum);
}
else{
//include the number dont include the number
return hmap[make_pair(i, sum)] = counter(n, i - 1, sum - i) + counter(n, i - 1, sum);
}
}
The function has starting values of N, N-1, and N, indicating number of elements, iterator(which decrements) and the sum of the recursive branch(which decreases with every included value).
This is the code that calculates the number of the subsets. for input of 3000 it takes around ~22 seconds to output the result which is 40 digits long. Because of the long digits i had to use an arbitrary precision library bigint from rgroshanrg, which works fine for values less than ~10000. Testing beyond that gives me a segfault on line 28-29, maybe due to the stored arbitrary precision values becoming too big and conflicting in the map. I need to somehow up this code so it can work with values beyond 10000 but i am stumped with it. Any ideas or should i switch towards another algorithm and data storage?
Here is a different algorithm, described in a paper by Evangelos Georgiadis, "Computing Partition Numbers q(n)":
std::vector<BigInt> RestrictedPartitionNumbers(int n)
{
std::vector<BigInt> q(n, 0);
// initialize q with A010815
for (int i = 0; ; i++)
{
int n0 = i * (3 * i - 1) >> 1;
if (n0 >= q.size())
break;
q[n0] = 1 - 2 * (i & 1);
int n1 = i * (3 * i + 1) >> 1;
if (n1 < q.size())
q[n1] = 1 - 2 * (i & 1);
}
// construct A000009 as per "Evangelos Georgiadis, Computing Partition Numbers q(n)"
for (size_t k = 0; k < q.size(); k++)
{
size_t j = 1;
size_t m = k + 1;
while (m < q.size())
{
if ((j & 1) != 0)
q[m] += q[k] << 1;
else
q[m] -= q[k] << 1;
j++;
m = k + j * j;
}
}
return q;
}
It's not the fastest algorithm out there, and this took about half a minute for on my computer for n = 300000. But you only need to do it once (since it computes all partition numbers up to some bound) and it doesn't take a lot of memory (a bit over 150MB).
The results go up to but excluding n, and they assume that for each number, that number itself is allowed to be a partition of itself eg the set {4} is a partition of the number 4, in your definition of the problem you excluded that case so you need to subtract 1 from the result.
Maybe there's a nicer way to express A010815, that part of the code isn't slow though, I just think it looks bad.
to find factors of number, i am using function void primeFactors(int n)
# include <stdio.h>
# include <math.h>
# include <iostream>
# include <map>
using namespace std;
// A function to print all prime factors of a given number n
map<int,int> m;
void primeFactors(int n)
{
// Print the number of 2s that divide n
while (n%2 == 0)
{
printf("%d ", 2);
m[2] += 1;
n = n/2;
}
// n must be odd at this point. So we can skip one element (Note i = i +2)
for (int i = 3; i <= sqrt(n); i = i+2)
{
// While i divides n, print i and divide n
while (n%i == 0)
{
int k = i;
printf("%d ", i);
m[k] += 1;
n = n/i;
}
}
// This condition is to handle the case whien n is a prime number
// greater than 2
if (n > 2)
m[n] += 1;
printf ("%d ", n);
cout << endl;
}
/* Driver program to test above function */
int main()
{
int n = 72;
primeFactors(n);
map<int,int>::iterator it;
int to = 1;
for(it = m.begin(); it != m.end(); ++it){
cout << it->first << " appeared " << it->second << " times "<< endl;
to *= (it->second+1);
}
cout << to << " total facts" << endl;
return 0;
}
You can check it here. Test case n = 72.
http://ideone.com/kaabO0
How do I solve above problem using above algo. (Can it be optimized more ?). I have to consider large numbers as well.
What I want to do ..
Take example for N = 864, we found X = 72 as (72 * 12 (no. of factors)) = 864)
There is a prime-factorizing algorithm for big numbers, but actually it is not often used in programming contests.
I explain 3 methods and you can implementate using this algorithm.
If you implementated, I suggest to solve this problem.
Note: In this answer, I use integer Q for the number of queries.
O(Q * sqrt(N)) solution per query
Your algorithm's time complexity is O(n^0.5).
But you are implementating with int (32-bit), so you can use long long integers.
Here's my implementation: http://ideone.com/gkGkkP
O(sqrt(maxn) * log(log(maxn)) + Q * sqrt(maxn) / log(maxn)) algorithm
You can reduce the number of loops because composite numbers are not neccesary for integer i.
So, you can only use prime numbers in the loop.
Algorithm:
Calculate all prime numbers <= sqrt(n) with Eratosthenes's sieve. The time complexity is O(sqrt(maxn) * log(log(maxn))).
In a query, loop for i (i <= sqrt(n) and i is a prime number). The valid integer i is about sqrt(n) / log(n) with prime number theorem, so the time complexity is O(sqrt(n) / log(n)) per query.
More efficient algorithm
There are more efficient algorithm in the world, but it is not used often in programming contests.
If you check "Integer factorization algorithm" on the internet or wikipedia, you can find the algorithm like Pollard's-rho or General number field sieve.
Well,I will show you the code.
# include <stdio.h>
# include <iostream>
# include <map>
using namespace std;
const long MAX_NUM = 2000000;
long prime[MAX_NUM] = {0}, primeCount = 0;
bool isNotPrime[MAX_NUM] = {1, 1}; // yes. can be improve, but it is useless when sieveOfEratosthenes is end
void sieveOfEratosthenes() {
//#see https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
for (long i = 2; i < MAX_NUM; i++) { // it must be i++
if (!isNotPrime[i]) //if it is prime,put it into prime[]
prime[primeCount++] = i;
for (long j = 0; j < primeCount && i * prime[j] < MAX_NUM; j++) { /*foreach prime[]*/
// if(i * prime[j] >= MAX_NUM){ // if large than MAX_NUM break
// break;
// }
isNotPrime[i * prime[j]] = 1; // set i * prime[j] not a prime.as you see, i * prime[j]
if (!(i % prime[j])) //if this prime the min factor of i,than break.
// and it is the answer why not i+=( (i & 1) ? 2 : 1).
// hint : when we judge 2,prime[]={2},we set 2*2=4 not prime
// when we judge 3,prime[]={2,3},we set 3*2=6 3*3=9 not prime
// when we judge 4,prime[]={2,3},we set 4*2=8 not prime (why not set 4*3=12?)
// when we judge 5,prime[]={2,3,5},we set 5*2=10 5*3=15 5*5=25 not prime
// when we judge 6,prime[]={2,3,5},we set 6*2=12 not prime,than we can stop
// why not put 6*3=18 6*5=30 not prime? 18=9*2 30=15*2.
// this code can make each num be set only once,I hope it can help you to understand
// this is difficult to understand but very useful.
break;
}
}
}
void primeFactors(long n)
{
map<int,int> m;
map<int,int>::iterator it;
for (int i = 0; prime[i] <= n; i++) // we test all prime small than n , like 2 3 5 7... it musut be i++
{
while (n%prime[i] == 0)
{
cout<<prime[i]<<" ";
m[prime[i]] += 1;
n = n/prime[i];
}
}
cout<<endl;
int to = 1;
for(it = m.begin(); it != m.end(); ++it){
cout << it->first << " appeared " << it->second << " times "<< endl;
to *= (it->second+1);
}
cout << to << " total facts" << endl;
}
int main()
{
//first init for calculate all prime numbers,for example we define MAX_NUM = 2000000
// the result of prime[] should be stored, you primeFactors will use it
sieveOfEratosthenes();
//second loop for i (i*i <= n and i is a prime number). n<=MAX_NUM
int n = 72;
primeFactors(n);
n = 864;
primeFactors(n);
return 0;
}
My best shot at performance without getting overboard with special algos.
The Erathostenes' seive - the complexity of the below is O(N*log(log(N))) - because the inner j loop starts from i*i instead of i.
#include <vector>
using std::vector;
void erathostenes_sieve(size_t upToN, vector<size_t>& primes) {
primes.clear();
vector<bool> bitset(upToN+1, true); // if the bitset[i] is true, the i is prime
bitset[0]=bitset[1]=0;
// if i is 2, will jump to 3, otherwise will jump on odd numbers only
for(size_t i=2; i<=upToN; i+=( (i&1) ? 2 : 1)) {
if(bitset[i]) { // i is prime
primes.push_back(i);
// it is enough to start the next cycle from i*i, because all the
// other primality tests below it are already performed:
// e.g:
// - i*(i-1) was surely marked non-prime when we considered multiples of 2
// - i*(i-2) was tested at (i-2) if (i-2) was prime or earlier (if non-prime)
for(size_t j=i*i; j<upToN; j+=i) {
bitset[j]=false; // all multiples of the prime with value of i
// are marked non-prime, using **addition only**
}
}
}
}
Now factoring based on the primes (set in a sorted vector). Before this, let's examine the myth of sqrt being expensive but a large bunch of multiplications is not.
First of all, let us note that sqrt is not that expensive anymore: on older CPU-es (x86/32b) it used to be twice as expensive as a division (and a modulo operation is division), on newer architectures the CPU costs are equal. Since factorisation is all about % operations again and again, one may still consider sqrt now and then (e.g. if and when using it saves CPU time).
For example consider the following code for an N=65537 (which is the 6553-th prime) assuming the primes has 10000 entries
size_t limit=std::sqrt(N);
size_t largestPrimeGoodForN=std::distance(
primes.begin(),
std::upper_limit(primes.begin(), primes.end(), limit) // binary search
);
// go descendingly from limit!!!
for(int i=largestPrimeGoodForN; i>=0; i--) {
// factorisation loop
}
We have:
1 sqrt (equal 1 modulo),
1 search in 10000 entries - at max 14 steps, each involving 1 comparison, 1 right-shift division-by-2 and 1 increment/decrement - so let's say a cost equal with 14-20 multiplications (if ever)
1 difference because of std::distance.
So, maximal cost - 1 div and 20 muls? I'm generous.
On the other side:
for(int i=0; primes[i]*primes[i]<N; i++) {
// factorisation code
}
Looks much simpler, but as N=65537 is prime, we'll go through all the cycle up to i=64 (where we'll find the first prime which cause the cycle to break) - a total of 65 multiplications.
Try this with a a higher prime number and I guarantee you the cost of 1 sqrt+1binary search are better use of the CPU cycle than all the multiplications on the way in the simpler form of the cycle touted as a better performance solution
So, back to factorisation code:
#include <algorithm>
#include <math>
#include <unordered_map>
void factor(size_t N, std::unordered_map<size_t, size_t>& factorsWithMultiplicity) {
factorsWithMultiplicity.clear();
while( !(N & 1) ) { // while N is even, cheaper test than a '% 2'
factorsWithMultiplicity[2]++;
N = N >> 1; // div by 2 of an unsigned number, cheaper than the actual /2
}
// now that we know N is even, we start using the primes from the sieve
size_t limit=std::sqrt(N); // sqrt is no longer *that* expensive,
vector<size_t> primes;
// fill the primes up to the limit. Let's be generous, add 1 to it
erathostenes_sieve(limit+1, primes);
// we know that the largest prime worth checking is
// the last element of the primes.
for(
size_t largestPrimeIndexGoodForN=primes.size()-1;
largestPrimeIndexGoodForN<primes.size(); // size_t is unsigned, so after zero will underflow
// we'll handle the cycle index inside
) {
bool wasFactor=false;
size_t factorToTest=primes[largestPrimeIndexGoodForN];
while( !( N % factorToTest) ) {
wasFactor=true;// found one
factorsWithMultiplicity[factorToTest]++;
N /= factorToTest;
}
if(1==N) { // done
break;
}
if(wasFactor) { // time to resynchronize the index
limit=std::sqrt(N);
largestPrimeIndexGoodForN=std::distance(
primes.begin(),
std::upper_bound(primes.begin(), primes.end(), limit)
);
}
else { // no luck this time
largestPrimeIndexGoodForN--;
}
} // done the factoring cycle
if(N>1) { // N was prime to begin with
factorsWithMultiplicity[N]++;
}
}
I am working on a assignment where I need to calculate the frequency of prime numbers from 1 to 10 million. we are to do this by taking variable U (which is 10 million) and dividing it into N parts and have multiple threads calculate the frequency of prime numbers, we must try this with different values for N and observe our processor ticks and time taken to calculate. The way the program works is 10 million is divided into N parts, upper and lower bounds are put into a vector of threads and each thread calls a function which counts the prime numbers.
now the frequency of primes from 1-million should be 664579. i am getting slightly inaccurate results when doing multiple threads. for example if i run the program with N=1, meaning only one thread will solve i get a frequency of 6645780, which is off by 1. N=2 i get the correct result of 664579, N=3 freq=664578, and so on. below is the code, any help is greatly appreciated.
#include <iostream>
#include <thread>
#include <vector>
#include<algorithm>
#define MILLION 1000000
using namespace std;
using std::for_each;
void frequencyOfPrimes(long long upper, long long lower, long long* freq)
{
long long i, j;
if (lower == 2) { *freq = upper; }
else { *freq = upper - lower; }
for (i = lower; i <= upper; ++i)
for (j = (long long)sqrt(i); j>1; --j)
if (i%j == 0) { --(*freq); break; }
return;
}
int main(int argc, char* argv[])
{
clock_t ticks = clock();
long long N = 10; //declare and initialize number of threads to calculate primes
long long U = 10*MILLION;
long long F=0; //total frequency
long long d = U / N; // the quotient of 10mil/number of threads
vector<thread> tV; //declare thread vector
vector<long long> f, u, l; //vector for freq, upper and lower bounds
f.resize(N);//initialize f
for (long long i = 0; i<N; i++) { //initialize and populate vectors for upper and lower bounds
if (i == 0) {
l.push_back(2);
u.push_back(d);
}
else {
l.push_back(u.at(i-1)+ 1);
u.push_back(u.at(i-1) + d);
}
}
u.at(N-1) = U; //make sure last thread has value of U for upper bound
for (long long i = 0; i < N; i++) { //initialize thread vectors
tV.push_back(thread(frequencyOfPrimes, u.at(i), l.at(i), &f.at(i)));
}
for_each(tV.begin(), tV.end(), mem_fn(&thread::join));
ticks = clock() - ticks;
for (long long i = 0; i < N; i++)
F = f.at(i) + F;
cout << "Frequency is " << F << endl;
cout << "It took " << ticks << " ticks (";
cout << ((float)ticks) / CLOCKS_PER_SEC << " seconds)" << endl;
this_thread::sleep_for(chrono::seconds(5));
return 0;
}
This has nothing to do with multi threading. Always test your functions:
#include <iostream>
#include <cmath>
using namespace std;
// this is your function with a shorter name
void fop_strange(long long upper, long long lower, long long* freq)
{
long long i, j;
if (lower == 2) { *freq = upper; }
else { *freq = upper - lower; }
for (i = lower; i <= upper; ++i)
for (j = (long long)sqrt(i); j>1; --j)
if (i%j == 0) { --(*freq); break; }
return;
}
// attention, I switched order of upper and lower
long long fop(long long a, long long b) {
long long f = 0;
fop_strange (b, a, &f);
return f;
}
int main() {
cout << fop(2, 4) << endl;
cout << fop(10, 14) << endl;
return 0;
}
Let's first count the primes manually:
2 to 4 (inclusive) => 2 (2, 3)
10 to 14 (inclusive) => 2 (11, 13)
Now your function (live on ideone)
3
1
Why? Well, you're correctly decreasing the count when you encounter a non prime, but you don't initialise it correctly. The range from 2 to 4 inclusive has 3 numbers, not 4. The range from 2 to 1 million has 1 million - 2 + 1, not 1 million numbers. The range from 10 to 14 inclusive has 5 numbers, not only 4. Etc.
This explains the results you're getting: For a range that starts from 2 your function returns 1 number more, fit every other range 1 number less. Therefore, when using only one thread and thus only a single range starting with 2 your result is one more, and every thread you add adds a range that brings one less, thus decreasing the overall result by one.
I am making a random number generator. It asks how many digits the user wants to be in the number. for example it they enter 2 it will generate random numbers between 10 and 99. I have made the generator but my issue is that the numbers are not unique.
Here is my code. I am not sure why it is not generating unique number. I thought srand(time(null)) would do it.
void TargetGen::randomNumberGen()
{
srand (time(NULL));
if (intLength == 1)
{
for (int i = 0; i< intQuantity; i++)
{
int min = 1;
int max = 9;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
else if (intLength == 2)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 10;
int max = 90;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
if (intLength == 3)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 100;
int max = 900;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
else if (intLength == 4)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 1000;
int max = 9000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
if (intLength == 5)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 10000;
int max = 90000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
else if (intLength == 6)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 100000;
int max = 900000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
if (intLength == 7)
{
for (int i = 0; i<intQuantity; i++)
{
int min = 1000000;
int max = 9000000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
else if (intLength == 8)
{
for (int i = 0; i <intQuantity; i++)
{
int min = 10000000;
int max = 89999999;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
if (intLength == 9)
{
for (int i = 0; i < intQuantity; i++)
{
int min = 100000000;
int max = 900000000;
int number1 = rand();
if (intQuantity > max)
{
intQuantity = max;
}
cout << number1 % max + min << "\t";
}
}
}
Okay so I thought I figured out a way to do this without arrays but It isn't working before I switch to the fisher yates method. Can someone tell me why this isn't working? It is supposed to essentially take the random number put that into variable numGen. Then in variable b = to numgen. Just to hold what numGen used to be so when the loop goes through and generates another random number it will compare it to what the old number is and if it is not equal to it, then it will output it. If it is equal to the old number than rather than outputting it, it will deincrement i so that it will run through the loop without skipping over the number entirely. However, when I do this is infinitely loops. And I am not sure why.
if (intLength == 1)
{
for (int i = 0; i< intQuantity; ++i)
{
int min = 1;
int max = 9;
int number1 = rand();
int numGen = number1 % max + min;
if (intQuantity > max)
{
intQuantity = max;
}
for (int k = 0; k < 1; k++)
{
cout << numGen << "\t";
int b = numGen;
}
int b = numGen;
if (b != numGen )
{
cout << numGen << "\t";
}
else
{
i--;
}
}
}
Everyone has interesting expectations for random numbers -- apparently, you expect random numbers to be unique! If you use any good random number generator, your random numbers will never be guaranteed to be unique.
To make this most obvious, if you wanted to generate random numbers in the range [1, 2], and you were to generate two numbers, you would (normally expect to) get one of the following four possibilities with equal probability:
1, 2
2, 1
1, 1
2, 2
It does not make sense to ask a good random number generator to generate the first two, but not the last two.
Now, take a second to think what to expect if you asked to generate three numbers in the same range... 1, 2, then what??
Uniqueness, therefore, is not, and will not be a property of a random number generator.
Your specific problem may require uniqueness, though. In this case, you need to do some additional work to ensure uniqueness.
One way is to keep a tab on which numbers are already picked. You can keep them in a set, and re-pick if you get one you got earlier. However, this is effective only if you pick a small set of numbers compared to your range; if you pick most of the range, the end of the process gets ineffective.
If the number count you are going to pick corresponds to most of the range, then using an array of the range, and the using a good shuffling algorithm to shuffle the numbers around is a better solution. (The Fisher-Yates shuffle should do the trick.)
Hint 0:
Use Quadratic residue from number theory; an integer q is called a quadratic residue modulo p if it is congruent to a perfect square modulo p; i.e., if there exists an integer x such that:
x2 ≡ q (mod p)
Hint 1:
Theorem: Assuming p is a prime number, the quadratic residue of x is unique as long as 2x < p. For example:
02 ≡ 0 (mod 13)
12 ≡ 1 (mod 13)
22 ≡ 4 (mod 13)
32 ≡ 9 (mod 13)
42 ≡ 3 (mod 13)
52 ≡ 12 (mod 13)
62 ≡ 10 (mod 13)
Hint 2:
Theorem: Assuming p is a prime number such that p ≡ 3 (mod 4), not only x2%p (i.e the quadratic residue) is unique for 2x < p but p - x2%p is also unique for 2x>p. For example:
02%11 = 0
12%11 = 1
22%11 = 4
32%11 = 9
42%11 = 5
52%11 = 3
11 - 62%11 = 8
11 - 72%11 = 6
11 - 82%11 = 2
11 - 92%11 = 7
11 - 102%11 = 10
Thus, this method provides us with a perfect 1-to-1 permutation on the integers less than p, where p can be any prime such that p ≡ 3 (mod 4).
Hint 3:
unsigned int UniqueRandomMapping(unsigned int x)
{
const unsigned int p = 11; //any prime number satisfying p ≡ 3 (mod 4)
unsigned int r = ((unsigned long long) x * x) % p;
if (x <= p / 2) return r;
else return p - r;
}
I didn't worry about the bad input numbers (e.g. out of the range).
Remarks
For 32-bit integers, you may choose the largest prime number such that p ≡ 3 (mod 4) which is less than 232 which is 4294967291.
Even though, this method gives you a 1-to-1 mapping for generating random number, it suffers from the clustering issue.
To improve the randomness of the aforementioned method, combine it with
other unique random mapping methods such as XOR operator.
I'll assume you can come up with a way to figure out how many numbers you want to use. It's pretty simple, since a user input of 2 goes to 10-99, 3 is 100-999, etc.
If you want to come up with your own implementation of unique, randomly generated numbers, check out these links.
http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Here is a very similar implementation: https://stackoverflow.com/a/196065/2142219
In essence, you're creating an array of X integers, all set to the value of their index. You randomly select an index between 0 and MAX, taking the value at this index and swapping it with the max value. MAX is then decremented by 1 and you can repeat it by randomly selecting an index between 0 and MAX - 1.
This gives you a random array of 0-999 integers with no duplicates.
Here are two possible approaches to generating unique random numbers in a range.
Keep track of which numbers you have already generated using std::set, and throw away and regenerate numbers as long as they are already in the set. This approach is not recommended if you want to generate a large number of random numbers, due to the birthday paradox.
Generate all numbers in your given range, take a random permutation of them, and output however many the user wants.
Standard random generators would never generate unique numbers, in this case they would Not be independent.
To generate unique numbers you have to:
Save all number generated and compare new one with old ones, if there is coincidence - regenerate.
or
Use random_shuffle function: http://en.cppreference.com/w/cpp/algorithm/random_shuffle to get all sequence in advance.
Firstly, srand()/rand() commonly have a period of 2^32, which means that after calling srand(), rand() will internally iterate over distinct integers during the first 2^32 calls to rand(). Still, rand() may well return a result with less than 32 bits: such as an int between 0 and RAND_MAX where RAND_MAX is 2^31-1 or 2^15-1, so you may see repeated results as the caller of rand(). You probably read about the period though, or somebody's comment made with awareness of that, and somehow it's been mistaken as uniqueness....
Secondly, given any call to rand() generates a number far larger than you want, and you're doing this...
number1 % max
The result of "number1 % max" is in the range 0 <= N <= max, but the random number itself may have been any multiple of max greater than that. In other words, two distinct random numbers that differ by a multiple of max still produce the same result for number1 % max in your program.
To get distinct random numbers within a range, you could prepopulate a std::vector with all the numbers, then std::shuffle them.
Please can any one provide with a better algorithm then trying all the combinations for this problem.
Given an array A of N numbers, find the number of distinct pairs (i,
j) such that j >=i and A[i] = A[j].
First line of the input contains number of test cases T. Each test
case has two lines, first line is the number N, followed by a line
consisting of N integers which are the elements of array A.
For each test case print the number of distinct pairs.
Constraints:
1 <= T <= 10
1 <= N <= 10^6
-10^6 <= A[i] <= 10^6 for 0 <= i < N
I think that first sorting the array then finding frequency of every distinct integer and then adding nC2 of all the frequencies plus adding the length of the string at last. But unfortunately it gives wrong ans for some cases which are not known help. here is the implementation.
code:
#include <iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long fun(long a) //to find the aC2 for given a
{
if (a == 1) return 0;
return (a * (a - 1)) / 2;
}
int main()
{
long t, i, j, n, tmp = 0;
long long count;
long ar[1000000];
cin >> t;
while (t--)
{
cin >> n;
for (i = 0; i < n; i++)
{
cin >> ar[i];
}
count = 0;
sort(ar, ar + n);
for (i = 0; i < n - 1; i++)
{
if (ar[i] == ar[i + 1])
{
tmp++;
}
else
{
count += fun(tmp + 1);
tmp = 0;
}
}
if (tmp != 0)
{
count += fun(tmp + 1);
}
cout << count + n << "\n";
}
return 0;
}
Keep a count of how many times each number appears in an array. Then iterate over the result array and add the triangular number for each.
For example(from the source test case):
Input:
3
1 2 1
count array = {0, 2, 1} // no zeroes, two ones, one two
pairs = triangle(0) + triangle(2) + triangle(1)
pairs = 0 + 3 + 1
pairs = 4
Triangle numbers can be computed by (n * n + n) / 2, and the whole thing is O(n).
Edit:
First, there's no need to sort if you're counting frequency. I see what you did with sorting, but if you just keep a separate array of frequencies, it's easier. It takes more space, but since the elements and array length are both restrained to < 10^6, the max you'll need is an int[10^6]. This easily fits in the 256MB space requirements given in the challenge. (whoops, since elements can go negative, you'll need an array twice that size. still well under the limit, though)
For the n choose 2 part, the part you had wrong is that it's an n+1 choose 2 problem. Since you can pair each one by itself, you have to add one to n. I know you were adding n at the end, but it's not the same. The difference between tri(n) and tri(n+1) is not one, but n.