What does this vector array code do? (C++) - c++

Having difficulty finding an explanation to this.
What does this code do? I understand it creates an array of vector but that's about it.
How can I print the vector array and access elements to experiment with it?
#define MAXN 300009
vector<int>dv[MAXN];
int main()
{
for(int i=1;i<MAXN;i++)
for(int j=i;j<MAXN;j+=i)
dv[j].push_back(i);
}

The code is easy enough to instrument. The reality of what it ends up producing is a very simple (and very inefficient) Sieve of Eratosthenes. Understanding that algorithm, you'll see what this code does to produce that ilk.
Edit: It is also a factor-table generator. See Edit below.
Instrumenting the code and dumping output afterward, and reducing the number of loops for simplification we have something like the following code. We use range-based-for loops for enumerating over each vector in the array of vectors:
#include <iostream>
#include <vector>
#define MAXN 20
std::vector<int>dv[MAXN];
int main()
{
for(int i=1;i<MAXN;i++)
{
for(int j=i;j<MAXN;j+=i)
dv[j].push_back(i);
}
for (auto const& v : dv)
{
for (auto x : v)
std::cout << x << ' ';
std::cout << '\n';
}
}
The resulting output is:
1
1 2
1 3
1 2 4
1 5
1 2 3 6
1 7
1 2 4 8
1 3 9
1 2 5 10
1 11
1 2 3 4 6 12
1 13
1 2 7 14
1 3 5 15
1 2 4 8 16
1 17
1 2 3 6 9 18
1 19
Now, note each vector that only has two elements (1 and an additional number). That second number is prime. In our test case those two-element vectors are:
1 2
1 3
1 5
1 7
1 11
1 13
1 17
1 19
In short, this is a very simple, and incredibly inefficient way of finding prime numbers. A slight change to the output loops to only output the second element of all vectors of length-two-only will therefore generate all the primes lower than MAXN. Therefore, using:
for (auto const& v : dv)
{
if (v.size() == 2)
std::cout << v[1] << '\n';
}
We will get all primes from [2...MAXN)
Edit: Factor Table Generation
If it wasn't obvious, each vector has an ending element (that not-coincidentally also lines up with the subscripts of the outer array). All preceding elements make up the positive factors of that number. For example:
1 2 5 10
is the dv[10] vector, and tells you 10 has factors 1,2,5,10. Likewise,
1 2 3 6 9 18
is the dv[18] vector, and tells you 18 has factors 1,2,3,6,9,18.
In short, if someone wanted to know all the factors of some number N that is < MAXN, this would be a way of putting all that info into tabular form.

Related

Is it safe to traverse a container during std::remove_if execution?

Suppose I want to remove the unique elements from an std::vector (not get rid of the duplicates, but retain only the elements that occur at least 2 times) and I want to achieve that in a pretty inefficient way - by calling std::count while std::remove_ifing. Consider the following code:
#include <algorithm>
#include <iostream>
#include <vector>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
return std::count(vec.begin(), vec.end(), n) == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
From reference on std::remove_if we know that the elements beginning from to_remove have unspecified values, but I wonder how unspecified they can really be.
To explain my concern a little further - we can see that the elements that should be removed are 1, 3, 5 and 7 - the only unique values. std::remove_if will move the 1 to the end but there is no guarantee that there will be a value 1 at the end after said operation. Can this be (due to that value being unspecified) that it will turn into 3 and make the std::count call return a count of (for example) 2 for the later encountered value 3?
Essentially my question is - is this guaranteed to work, and by work I mean to inefficiently erase unique elements from an std::vector?
I am interested in both language-lawyer answer (which could be "the standard says that this situation is possible, you should avoid it") and in-practice answer (which could be "the standard says that this situation is possible, but realistically there is no way of this value ending up as a completely differeny one, for example 3").
After the predicate returns true the first time, there will be one unspecified value in the range. That means any subsequent calls of the predicate will count an unspecified value. The count is therefore potentially incorrect, and you may either leave values unaffected that you intend to be discarded, or discard values that should be retained.
You could modify the predicate so it keeps a count of how many times it has returned true, and reduce the range accordingly. For example;
std::size_t count = 0;
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec, &count](int n)
{
bool once = (std::count(vec.begin(), vec.end() - count, n) == 1);
if (once) ++count;
return once;
});
Subtracting an integral value from a vector's end iterator is safe, but that isn't necessarily true for other containers.
You misunderstood how std::remove_if works. The to-be-removed values are not necessarily shifted to the end. See:
Removing is done by shifting (by means of move assignment) the elements in the range in such a way that the elements that are not to be removed appear in the beginning of the range. cppreference
This is the only guarantee for the state of the range. According to my knowledge, it's not forbidden to shift all values around and it would still satisfy the complexity. So it might be possible that some compilers shift the unwanted values to the end but that would be just extra unnecessary work.
An example of possible implementation of removing odd numbers from 1 2 3 4 8 5:
v - read position
1 2 3 4 8 5 - X will denotes shifted from value = unspecified
^ - write position
v
1 2 3 4 8 5 1 is odd, ++read
^
v
2 X 3 4 8 5 2 is even, *write=move(*read), ++both
^
v
2 X 3 4 8 5 3 is odd, ++read
^
v
2 4 3 X 8 5 4 is even, *write=move(*read), ++both
^
v
2 4 8 X X 5 8 is even, *write=move(*read), ++both
^
2 4 8 X X 5 5 is odd, ++read
^ - this points to the new end.
So, in general, you cannot rely on count returning any meaningful values. Since in the case that move==copy (as is for ints) the resulting array is 2 4 8|4 8 5. Which has incorrect count both for the odd and even numbers. In case of std::unique_ptr the X==nullptr and thus the count for nullptr and removed values might be wrong. Other remaining values should not be left in the end part of the array as there were no copies done.
Note that the values are not unspecified as in you cannot know them. They are exactly the results of move assignments which might leave the value in unspecified state. If it specified the state of the moved-from variables ( asstd::unique_ptr does) then they would be known. E.g. if move==swap then the range will be permuted only.
I added some outputs:
#include <algorithm>
#include <iostream>
#include <vector>
#include <mutex>
int main() {
std::vector<int> vec = {1, 2, 6, 3, 6, 2, 7, 4, 4, 5, 6};
auto to_remove = std::remove_if(vec.begin(), vec.end(), [&vec](int n) {
std::cout << "number " << n << ": ";
for (auto i : vec) std::cout << i << ' ';
auto c = std::count(vec.begin(), vec.end(), n);
std::cout << ", count: " << c << std::endl;
return c == 1;
});
vec.erase(to_remove, vec.end());
for (int i : vec) std::cout << i << ' ';
}
and got
number 1: 1 2 6 3 6 2 7 4 4 5 6 , count: 1
number 2: 1 2 6 3 6 2 7 4 4 5 6 , count: 2
number 6: 2 2 6 3 6 2 7 4 4 5 6 , count: 3
number 3: 2 6 6 3 6 2 7 4 4 5 6 , count: 1
number 6: 2 6 6 3 6 2 7 4 4 5 6 , count: 4
number 2: 2 6 6 3 6 2 7 4 4 5 6 , count: 2
number 7: 2 6 6 2 6 2 7 4 4 5 6 , count: 1
number 4: 2 6 6 2 6 2 7 4 4 5 6 , count: 2
number 4: 2 6 6 2 4 2 7 4 4 5 6 , count: 3
number 5: 2 6 6 2 4 4 7 4 4 5 6 , count: 1
number 6: 2 6 6 2 4 4 7 4 4 5 6 , count: 3
2 6 6 2 4 4 6
As you can see the counts can be wrong. I'm not able to create an example for your special case but as a rule you have to worry about wrong results.
First the number 4 is counted twice and in the next step the number 4 is counted thrice. The counts are wrong and you can't rely on them.

Optimize triplet summation in C++

Problem
I need to compute a function of an array of integers. For every three-element subset (or triplet) of the array, I need to compute the term floor((sum of triplet)/(product of triplet)). Then I need to return the sum of all such terms.
Example
Input (length; array):
5
1 2 1 7 3
Output:
6
Explanation
The following triplets exist in the given array:
1 2 1
1 2 7
1 2 3
1 1 7
1 1 3
1 7 3
2 1 7
2 1 3
2 7 3
1 7 3
Considering these triplets from the sample input:
1 2 1 contributes 2, because floor((1+2+1)/(1*2*1)) = floor(4/2) = 2
1 2 3 contributes 1
1 1 7 contributes 1
1 1 3 contributes 1
2 1 3 contributes 1
All other triplets contribute 0 to the sum.
Hence the answer is (2+1+1+1+1)=6.
My Solution
What I tried is complexity O(n^3). Code is given below:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
long t,n[300005],sum=0,mul=1,i,j,k,res=0;
cin >> t;
for(i=0;i<t;i++)
cin >>n[i];
for(i=0;i<t-2;i++)
for(j=i+1;j<t-1;j++)
for(k=j+1;k<t;k++)
{
sum = n[i]+n[j]+n[k];
mul = n[i]*n[j]*n[k];
res += floor(sum/mul);
}
cout << res << endl;
return 0;
}
Is there any hint of better optimization?
While still O(n^3), you could save some operations by caching the redundant calculations between n[i] and n[j] as you iterate over n[k].
For example:
long sum_ij,mul_ij;
for(i=0;i<t-2;i++) {
for(j=i+1;j<t-1;j++) {
sum_ij = n[i]+n[j];
mul_ij = n[i]*n[j];
for(k=j+1;k<t;k++)
{
sum = sum_ij+n[k];
mul = mul_ij*n[k];
res += floor(sum/mul);
}
}
}

Formula Sequence

I need help finding the formula of the sequence for the next problem.
What I think and have for now is Sn=n(10^n-1)/9 but it just works in some cases...
Here is the description of the problem:
Description
Sn is based upon the sequence positive integers numbers. The value n can be found n times, so the first 25 terms of this sequence are as follows:
1 2 2 3 3 3 4 4 4 4 5 5 5 5 5 6 6 6 6 6 6 7 7 7 7...
For this problem, you have to write a program that calculates the i-th term in the sequence. That is, determine Sn(i).
Input specification
Input may contain several test cases (but no more than 10^5). Each test case is given in a line of its own, and contains an integer i (1 <= i <= 2 * 10^9). Input ends with a test case in which i is 0, and this case must not be processed.
Output specification
For each test case in the input, you must print the value of Sn(i) in a single line.
Sample input
1
25
100
0
Sample output
1
7
14
Thanks solopilot! I made the code but the online judge show me Time Limit Exceeded, what could be my error?
#include <iostream> #include <math.h> using namespace std; int main() {int i;
int NTS;
cin>>i;
while (i>=1){
NTS=ceil((sqrt(8*i+1)-1)/2);
cout<<" "<<NTS<<endl;
cin>>i;
}
return 0;}
F(n) = ceiling((sqrt(8*n+1)-1)/2)
Say F(n) = a.
Then n ~= a * (a+1) / 2.
Rearranging: a^2 + a - 2n ~= 0.
Solving: a = F(n) = (-1 + sqrt(1+8n)) / 2.
Ignore the negative answer.
The pattern looks like a pyramid.
Level : 1 3 6 10 15 21 28...
No : 1 2 3 4 5 6 7...
Level = n(n+1)/2 => elements
3 = 3*4/2 => 6
6 = 6*7/2 => 21

Using recursion combinations to subset array [duplicate]

This question already exists:
Recursion all combinations of lower triangle C++
Closed 8 years ago.
I recently posted a poor question on how to use recursion to estimate all combinations of lower triangle in C++. I managed to find a recursive algorithm that given an array of size n, generates and prints all possible combinations of r elements in array. I've employed this function using Rcpp in R. I've then written a loop around this function to get all the subsets of combinations r to r + n.
#include <Rcpp.h>
using namespace Rcpp;
// [[Rcpp::export]]
int recursive(IntegerVector arr, IntegerVector data, int start, int end, int index, int r)
{
if (index == r)
{
for (int j=0; j<r; j++)
printf("%d ", data[j]);
printf("\n");
}
for (int i=start; i<=end && end-i+1 >= r-index; i++)
{
data[index] = arr[i];
recursive(arr, data, i+1, end, index+1, r);
}
}
R code with five groups:
Rcpp::sourceCpp('recursive2.cpp')
nComm <- 5
r <- c(2:nComm)
n <- nComm
arr <- c(1:nComm)
dat <- c(1:nComm)
for(i in 1:(n-1)){
recursive(arr, dat, 0, n-1, 0, r[i])
}
1 2
1 3
1 4
1 5
2 3
2 4
2 5
3 4
3 5
4 5
1 2 3
1 2 4
1 2 5
1 3 4
1 3 5
1 4 5
2 3 4
2 3 5
2 4 5
3 4 5
1 2 3 4
1 2 3 5
1 2 4 5
1 3 4 5
2 3 4 5
1 2 3 4 5
Currently, this just prints the subsets of combinations I need to estimate my dissimilarities. I'd like to be able to remove the loop and use it as a single Rcpp function/script. With the end goal to be able to use the subsets (currently printed combinations) as way to subset rows in an array. Which will be used to calculate the intersect between vectors. So 1 2 will be used to compare rows 1 and 2 in an array. And so forth.

Permutations with some fixed numbers

How to effectively generate permutations of a number (or chars in word), if i need some char/digit on specified place?
e.g. Generate all numbers with digit 3 at second place from the beginning and digit 1 at second place from the end of the number. Each digit in number has to be unique and you can choose only from digits 1-5.
4 3 2 1 5
4 3 5 1 2
2 3 4 1 5
2 3 5 1 4
5 3 2 1 4
5 3 4 1 2
I know there's a next_permutation function, so i can prepare an array with numbers {4, 2, 5} and post this in cycle to this function, but how to handle the fixed positions?
Generate all permutations of 2 4 5 and insert 3 and 1 in your output routine. Just remember the positions were they have to be:
int perm[3] = {2, 4, 5};
const int N = sizeof(perm) / sizeof(int);
std::map<int,int> fixed; // note: zero-indexed
fixed[1] = 3;
fixed[3] = 1;
do {
for (int i=0, j=0; i<5; i++)
if (fixed.find(i) != fixed.end())
std::cout << " " << fixed[i];
else
std::cout << " " << perm[j++];
std::cout << std::endl;
} while (std::next_permutation(perm, perm + N));
outputs
2 3 4 1 5
2 3 5 1 4
4 3 2 1 5
4 3 5 1 2
5 3 2 1 4
5 3 4 1 2
I've read the other answers and I believe they are better than mine for your specific problem. However I'm answering in case someone needs a generalized solution to your problem.
I recently needed to generate all permutations of the 3 separate continuous ranges [first1, last1) + [first2, last2) + [first3, last3). This corresponds to your case with all three ranges being of length 1 and separated by only 1 element. In my case the only restriction is that distance(first3, last3) >= distance(first1, last1) + distance(first2, last2) (which I'm sure could be relaxed with more computational expense).
My application was to generate each unique permutation but not its reverse. The code is here:
http://howardhinnant.github.io/combinations.html
And the specific applicable function is combine_discontinuous3 (which creates combinations), and its use in reversible_permutation::operator() which creates the permutations.
This isn't a ready-made packaged solution to your problem. But it is a tool set that could be used to solve generalizations of your problem. Again, for your exact simple problem, I recommend the simpler solutions others have already offered.
Remember at which places you want your fixed numbers. Remove them from the array.
Generate permutations as usual. After every permutation, insert your fixed numbers to the spots where they should appear, and output.
If you have a set of digits {4,3,2,1,5} and you know that 3 and 1 will not be permutated, then you can take them out of the set and just generate a powerset for {4, 2, 5}. All you have to do after that is just insert 1 and 3 in their respective positions for each set in the power set.
I posted a similar question and in there you can see the code for a powerset.