Prime number finder runtime error - c++

Using a variant of sieve of eratosthenes I wrote a piece of code in c++ which ought to calculate prime numbers and store them in a vector.
In the first part i took array ar of length 1000 using calloc() so that i get the values initialized as false of every array element and calculated and stored primes less than 1000 in the vector a.
In the second part I took values start and end , so that I'll find next prime numbers in range [start,end).
The code is working fine to calculate prime numbers (0,10000) but is giving runtime error if range to find prime numbers is greater than that.
Below is my code.
#include<bits/stdc++.h>
using namespace std;
int main()
{
bool *ar=(bool*)calloc(1000,sizeof(bool));
vector<int> a;
for(int i=2;i<1000;i++)
{
if(!ar[i])
{
a.push_back(i);
for(int j=i*i;j<1000;j+=i)
ar[j]=true;
}
}
int start=1000,end=2000;
while(start<10000)
{
for(int i=0;i<1000;i++)
ar[i]=false;
for(int i=0;i<a.size();i++)
{
int m=start/a[i];
if(start%a[i]>0)
m++;
for(int j=a[i]*m;j<end;j+=a[i])
ar[j-start]=true;
}
for(int i=0;i<1000;i++)
{
if(!ar[i])
{
a.push_back(i+start);
for(int j=(i+start)*(i+start);j<end;j+=i+start)
ar[j-start]=true;
}
}
start+=1000;
end+=1000;
}
for(int i=0;i<a.size();i++)
cout<<a[i]<<' ';
return 0;
}

I recommend static declaration of array ar bool ar[1000]; and then put assertion before accessing array ar, since there is some issue with your calculation. When you run your code, your IDE will stop before writing outside the array boundaries
a.push_back(i+start);
for(int j=(i+start)*(i+start);j<end;j+=i+start)
{
assert(j-start >= 0 && j-start < 1000);
ar[j-start]=true;
}

Related

Why does the function return 0?

I have this function that should take a matrix, compare the diagonal elements of the matrix and find the smallest one.
Here it should compare y[0][1] and y[1][0].
#include <iostream>
int Min(int, int [][2]);
using namespace std;
int main() {
int min, y[2][2];
y[0][0]=5;
y[0][1]=4;
y[1][0]=-9;
y[1][1]=0;
min = Min(2, y);
cout<<min;
return 0;
}
int Min(int k, int x[][2]){
int min=x[0][0];
for(int i=0; i<k;i++){
if(x[i][i]<min){
min=x[i][i];
}
}
return min;
}
It always returns 0. Why?
Here it should compare y[0][1] and y[1][0].
Your function goes through the diagonal of the matrix, it hence checks y[0][0] and y[1][1]. They are 5 and 0. The result is zero, which is to be expected.
Here it should compare y[0][1] and y[1][0].
But that's not what you say here:
int min=x[0][0];
or here:
if(x[i][i]<min){
min=x[i][i];
}
Since i cannot be both 0 and 1 at the same time, this accesses x[0][0] and x[1][1].
And for those elements, 0 is the correct minimum.
As a side note, your Min function can only work with matrices of size 2, so the k parameter is unnecessary. Multi-dimensional arrays are annoying like that.
To iterate over all items instead of just [0][0] and [1][1] you need to do:
for(int i=0; i<k; i++)
{
for(int j=0; j<k; j++)
{
if(x[i][j]<min)
{
min=x[i][j];
}
}
}
int Min(int k,const int x[][2])
{
int min=x[0][0];
for(int i=0; i<k;i++)
{
for(int j=0;j<k;j++)
{
if(x[i][j]<min)
{
min=x[i][j];
}
}
}
Earlier it was always showing zero because it had a mess with the column index. Outer for loop iterates k-1 times with first iteration at i=0, and second at i=1 and during both iterations it assigns the same index to both row and column(i.e., x [0][0] and x[1][1]). Perhaps it must assign the index x[0][0], x[0][1], x[1][0], x[1][1]. Earlier, it had only two iterations(the outer for loop) but now it takes four iterations assigning the appropriate index to both column and rows the efficient number of times.

Array doesn't print anything on executing code

I was creating a function that takes an integer number, finds the next multiple of 5 after the number and then if the difference between the multiple and the number is less than 3, then it prints out the multiple else the number itself, finally prints out an array of all the numbers.
#include <bits/stdc++.h>
#include <iostream>
using namespace std;
vector<int> gradingStudents(vector<int> grades) {
int size=grades.size();
int c=0;
int d;
vector<int> array;
for(int i=0;i<size;i++){
while(grades[i]>(c*5)){
c++;
}
d=c*5;
if((d-grades[i])<3){
array[i]=d;
}else{
array[i]=grades[i];
}
d=0;
c=0;
}
return array ;
Now I tried running this function, and the compiler gives shows no error in the program in the code, however the code doesn't print anything.
Someone Please help.
First, I have to say that this code is extremely inefficient. Finding the difference between the closest muliplication of 5 and a number can be simply done by:
int difference = (n - (n + 4) / 5 * 5) - n;
Explanation: C++ is rounding down the division, so (n + 4) / 5 is n / 5 rounded up, and hence (n+4)/5*5 is the closest multiplication of 5.
Another thing, you declare an array but never resize it, so its size is 0. You need to resize it either by specifying the size in the constructor or using the std::vector::resize method.
code:
std::vector<int> gradingStudents(std::vector<int> grades) {
std::size_t size = grades.size();
std::vector<int> array(size);
for (int i = 0; i < size; i++) {
int closestMul = (grades[i] + 4) / 5 * 5;
if (closestMul - grades[i] < 3) {
array[i] = closestMul;
}
else {
array[i] = grades[i];
}
}
return array;
}
Proably your code is crashing, which is why it doesn't print anything. And one reason it might be crashing is your vector use is wrong.
It's very common to see beginners write code like this
vector<int> array;
for (int i=0;i<size;i++) {
array[i] = ...;
But your vector has zero size. So array[i] is an error, always.
Two possible solutions
1) Make the vector the correct size to begin with
vector<int> array(size);
for (int i=0;i<size;i++) {
array[i] = ...;
2) Use push_back to add items to the vector, every time you call push_back the vector increases in size by one.
vector<int> array(size);
for (int i=0;i<size;i++) {
array.push_back(...);
And please don't call your vector array, that's just taking the piss.
i feel nothing is wrong with your function but calling of this function is a bit tricky let me give you a quick main to try may be that will help you.
int main() {
vector <int> test ;
test.push_back(1);
test.push_back(2);
gradingStudents(test);
return 0;
}
Try initially the size of the vector is empty i hope you are sending something from the main . Your code is very inefficient whenever you find time must read how to write an efficient code.

Count number of ways for choosing two numbers in efficient algorithm

I solved this problem but I got TLE Time Limit Exceed on online judge
the output of program is right but i think the way can be improved to be more efficient!
the problem :
Given n integer numbers, count the number of ways in which we can choose two elements such
that their absolute difference is less than 32.
In a more formal way, count the number of pairs (i, j) (1 ≤ i < j ≤ n) such that
|V[i] - V[j]| < 32. |X|
is the absolute value of X.
Input
The first line of input contains one integer T, the number of test cases (1 ≤ T ≤ 128).
Each test case begins with an integer n (1 ≤ n ≤ 10,000).
The next line contains n integers (1 ≤ V[i] ≤ 10,000).
Output
For each test case, print the number of pairs on a single line.
my code in c++ :
int main() {
int T,n,i,j,k,count;
int a[10000];
cin>>T;
for(k=0;k<T;k++)
{ count=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
}
for(i=0;i<n;i++)
{
for(j=i;j<n;j++)
{
if(i!=j)
{
if(abs(a[i]-a[j])<32)
count++;
}
}
}
cout<<count<<endl;
}
return 0;
}
I need help how can I solve it in more efficient algorithm ?
Despite my previous (silly) answer, there is no need to sort the data at all. Instead you should count the frequencies of the numbers.
Then all you need to do is keep track of the number of viable numbers to pair with, while iterating over the possible values. Sorry no c++ but java should be readable as well:
int solve (int[] numbers) {
int[] frequencies = new int[10001];
for (int i : numbers) frequencies[i]++;
int solution = 0;
int inRange = 0;
for (int i = 0; i < frequencies.length; i++) {
if (i > 32) inRange -= frequencies[i - 32];
solution += frequencies[i] * inRange;
solution += frequencies[i] * (frequencies[i] - 1) / 2;
inRange += frequencies[i];
}
return solution;
}
#include <bits/stdc++.h>
using namespace std;
int a[10010];
int N;
int search (int x){
int low = 0;
int high = N;
while (low < high)
{
int mid = (low+high)/2;
if (a[mid] >= x) high = mid;
else low = mid+1;
}
return low;
}
int main() {
cin >> N;
for (int i=0 ; i<N ; i++) cin >> a[i];
sort(a,a+N);
long long ans = 0;
for (int i=0 ; i<N ; i++)
{
int t = search(a[i]+32);
ans += (t -i - 1);
}
cout << ans << endl;
return 0;
}
You can sort the numbers, and then use a sliding window. Starting with the smallest number, populate a std::deque with the numbers so long as they are no larger than the smallest number + 31. Then in an outer loop for each number, update the sliding window and add the new size of the sliding window to the counter. Update of the sliding window can be performed in an inner loop, by first pop_front every number that is smaller than the current number of the outer loop, then push_back every number that is not larger than the current number of the outer loop + 31.
One faster solution would be to first sort the array, then iterate through the sorted array and for each element only visit the elements to the right of it until the difference exceeds 31.
Sorting can probably be done via count sort (since you have 1 ≤ V[i] ≤ 10,000). So you get linear time for the sorting part. It might not be necessary though (maybe quicksort suffices in order to get all the points).
Also, you can do a trick for the inner loop (the "going to the right of the current element" part). Keep in mind that if S[i+k]-S[i]<32, then S[i+k]-S[i+1]<32, where S is the sorted version of V. With this trick the whole algorithm turns linear.
This can be done constant number of passes over the data, and actually can be done without being affected by the value of the "interval" (in your case, 32).
This is done by populating an array where a[i] = a[i-1] + number_of_times_i_appears_in_the_data - informally, a[i] holds the total number of elements that are smaller/equals to i.
Code (for a single test case):
static int UPPER_LIMIT = 10001;
static int K = 32;
int frequencies[UPPER_LIMIT] = {0}; // O(U)
int n;
std::cin >> n;
for (int i = 0; i < n; i++) { // O(n)
int x;
std::cin >> x;
frequencies[x] += 1;
}
for (int i = 1; i < UPPER_LIMIT; i++) { // O(U)
frequencies[i] += frequencies[i-1];
}
int count = 0;
for (int i = 1; i < UPPER_LIMIT; i++) { // O(U)
int low_idx = std::max(i-32, 0);
int number_of_elements_with_value_i = frequencies[i] - frequencies[i-1];
if (number_of_elements_with_value_i == 0) continue;
int number_of_elements_with_value_K_close_to_i =
(frequencies[i-1] - frequencies[low_idx]);
std::cout << "i: " << i << " number_of_elements_with_value_i: " << number_of_elements_with_value_i << " number_of_elements_with_value_K_close_to_i: " << number_of_elements_with_value_K_close_to_i << std::endl;
count += number_of_elements_with_value_i * number_of_elements_with_value_K_close_to_i;
// Finally, add "duplicates" of i, this is basically sum of arithmetic
// progression with d=1, a0=0, n=number_of_elements_with_value_i
count += number_of_elements_with_value_i * (number_of_elements_with_value_i-1) /2;
}
std::cout << count;
Working full example on IDEone.
You can sort and then use break to end loop when ever the range goes out.
int main()
{
int t;
cin>>t;
while(t--){
int n,c=0;
cin>>n;
int ar[n];
for(int i=0;i<n;i++)
cin>>ar[i];
sort(ar,ar+n);
for(int i=0;i<n;i++){
for(int j=i+1;j<n;j++){
if(ar[j]-ar[i] < 32)
c++;
else
break;
}
}
cout<<c<<endl;
}
}
Or, you can use a hash array for the range and mark occurrence of each element and then loop around and check for each element i.e. if x = 32 - y is present or not.
A good approach here is to split the numbers into separate buckets:
constexpr int limit = 10000;
constexpr int diff = 32;
constexpr int bucket_num = (limit/diff)+1;
std::array<std::vector<int>,bucket_num> buckets;
cin>>n;
int number;
for(i=0;i<n;i++)
{
cin >> number;
buckets[number/diff].push_back(number%diff);
}
Obviously the numbers that are in the same bucket are close enough to each other to fit the requirement, so we can just count all the pairs:
int result = std::accumulate(buckets.begin(), buckets.end(), 0,
[](int s, vector<int>& v){ return s + (v.size()*(v.size()-1))/2; });
The numbers that are in non-adjacent buckets cannot form any acceptable pairs, so we can just ignore them.
This leaves the last corner case - adjacent buckets - which can be solved in many ways:
for(int i=0;i<bucket_num-1;i++)
if(buckets[i].size() && buckets[i+1].size())
result += adjacent_buckets(buckets[i], buckets[i+1]);
Personally I like the "occurrence frequency" approach on the one bucket scale, but there may be better options:
int adjacent_buckets(const vector<int>& bucket1, const vector<int>& bucket2)
{
std::array<int,diff> pairs{};
for(int number : bucket1)
{
for(int i=0;i<number;i++)
pairs[i]++;
}
return std::accumulate(bucket2.begin(), bucket2.end(), 0,
[&pairs](int s, int n){ return s + pairs[n]; });
}
This function first builds an array of "numbers from lower bucket that are close enough to i", and then sums the values from that array corresponding to the upper bucket numbers.
In general this approach has O(N) complexity, in the best case it will require pretty much only one pass, and overall should be fast enough.
Working Ideone example
This solution can be considered O(N) to process N input numbers and constant in time to process the input:
#include <iostream>
using namespace std;
void solve()
{
int a[10001] = {0}, N, n, X32 = 0, ret = 0;
cin >> N;
for (int i=0; i<N; ++i)
{
cin >> n;
a[n]++;
}
for (int i=0; i<10001; ++i)
{
if (i >= 32)
X32 -= a[i-32];
if (a[i])
{
ret += a[i] * X32;
ret += a[i] * (a[i]-1)/2;
X32 += a[i];
}
}
cout << ret << endl;
}
int main()
{
int T;
cin >> T;
for (int i=0 ; i<T ; i++)
solve();
}
run this code on ideone
Solution explanation: a[i] represents how many times i was in the input series.
Then you go over entire array and X32 keeps track of number of elements that's withing range from i. The only tricky part really is to calculate properly when some i is repeated multiple times: a[i] * (a[i]-1)/2. That's it.
You should start by sorting the input.
Then if your inner loop detects the distance grows above 32, you can break from it.
Thanks for everyone efforts and time to solve this problem.
I appreciated all Attempts to solve it.
After testing the answers on online judge I found the right and most efficient solution algorithm is Stef's Answer and AbdullahAhmedAbdelmonem's answer also pavel solution is right but it's exactly same as Stef solution in different language C++.
Stef's code got time execution 358 ms in codeforces online judge and accepted.
also AbdullahAhmedAbdelmonem's code got time execution 421 ms in codeforces online judge and accepted.
if they put detailed explanation to there algorithm the bounty will be to one of them.
you can try your solution and submit it to codeforces online judge at this link after choosing problem E. Time Limit Exceeded?
also I found a great algorithm solution and more understandable using frequency array and it's complexity O(n).
in this algorithm you only need to take specific range for each inserted element to the array which is:
begin = element - 32
end = element + 32
and then count number of pair in this range for each inserted element in the frequency array :
int main() {
int T,n,i,j,k,b,e,count;
int v[10000];
int freq[10001];
cin>>T;
for(k=0;k<T;k++)
{
count=0;
cin>>n;
for(i=1;i<=10000;i++)
{
freq[i]=0;
}
for(i=0;i<n;i++)
{
cin>>v[i];
}
for(i=0;i<n;i++)
{
count=count+freq[v[i]];
b=v[i]-31;
e=v[i]+31;
if(b<=0)
b=1;
if(e>10000)
e=10000;
for(j=b;j<=e;j++)
{
freq[j]++;
}
}
cout<<count<<endl;
}
return 0;
}
finally i think the best approach to solve this kind of problems to use frequency array and count number of pairs in specific range because it's time complexity is O(n).

SPOJ SUMFOUR.....TLE on test case 9

I am trying to solve SPOJ Problem SUMFOUR....I am geting TLE on test case 9 http://www.spoj.com/problems/SUMFOUR/
So,Which part of my code has to be edited and how?Here N<=4000
#include <iostream>
#include<string>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<map>
#include<vector>
using namespace std;
int main()
{
int a[4005][5],n;
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=4;j++)
scanf("%d",&a[i][j]);
int k=0;
for(int i=1;i<=n;i++)
{ int p=a[i][1];
for(int j=1;j<=n;j++)
{ b.push_back(p+a[j][2]);
k++;
}
}
k=0;
for(int i=1;i<=n;i++)
{ int p=a[i][3];
for(int j=1;j<=n;j++)
{ c.push_back(p+a[j][4]);
k++;
}
}
sort(b.begin(),b.end());
int cnt=0;
for(int j=0;j<k;j++)
if(find(b.begin(),b.end(),-c[j])!=b.end() )
cnt=cnt+count(b.begin(),b.end(),-c[j]) ;
printf("%d\n",cnt);
return 0;
}
The problem is here:
for(int j=0;j<k;j++)
if(find(b.begin(),b.end(),-c[j])!=b.end() )
cnt=cnt+count(b.begin(),b.end(),-c[j]) ;
for n = 4000, so there are 4000^2 elements in b and c. So, the time complexity for this loop is 4000^4, as find and count time complexity is O(n), which of course will cause you time limit exceed.
So, how you can reduce the time? You can use binary search to faster the count process, which reduce the time complexity of the above loop to O(n^2 log n), as I notice you already sort b.
Or , you can use map to count and store the frequency of each element in b and c.
map<long long, int> b;
map<long long, int> c;
for(int i=1;i<=n;i++)
{ long long p=a[i][1];
for(int j=1;j<=n;j++)
{
long long tmp =p + a[j][2];
b[tmp] = b[tmp] + 1;
}
}
// Similar for c
map <long long, int>::iterator it;
long long result;
for (it = c.begin(); it != c.end(); ++it)
result += c[it->first]*b[-(it->first)];
For your new update, please change this:
for(int j=1;j<=n;j++)
{ if( b.count(a[i][1]+a[j][2]) )
{ b[a[i][1]+a[j][2]]+=1;
c[a[i][3]+a[j][4]]+=1;
}
else
{ b[a[i][1]+a[j][2]]=1;
c[a[i][3]+a[j][4]]=1;
}
}
into this:
for(int j=1;j<=n;j++)
{
b[a[i][1]+a[j][2]]+=1;
c[a[i][3]+a[j][4]]+=1;
}
The condition check if( b.count(a[i][1]+a[j][2]) ) is for b only, and you use it for c, which make c incorrect.
Update: After trying to get accepted in SPOJ, it turns out that map is not fast enough, so I make a change into binary search, and got accepted.
My accepted code
Please Don't Use Map as its worst Case Complexity Can be O(log(n)) .
SO instead You can just Use two sorted arrays and for every element as in the
first array , Binary Search for its -ve agent in the Second Cumulative array .
Just Change the find method in Last lines to Binary search(c.begin(),c.end(),key) and find the repititons till the end with that index as it gives the lower_bound index .
That Total Sum gives the answer and its expected Complexity is
O(n^2log(n)).

Return the count of negative numbers in the optimal way

A variation of "Searching in a Matrix that is sorted rowwise and columnwise"
Given a 2D Matrix that is sorted rowwise and columnwise. You have to return the count of negative numbers in most optimal way.
I could think of this solution
initialise rowindex=0
if rowindex>0 rowindex++
else apply binary search
And implemented in with this code for 5X5 matrix
#include<iostream>
#include<cstdio>
using namespace std;
int arr[5][5];
int func(int row)
{
int hi=4;
int lo=0;
int mid=(lo+hi)/2;
while(hi>=lo)
{
mid=(lo+hi)/2;
.
if(mid==4)
{
return 5;
}
if(arr[row][mid]<0 && arr[row][mid+1]<0)
{
lo=mid+1;
}
else if(arr[row][mid]>0 && arr[row][mid+1]>0)
{
hi=mid-1;
}
else if(arr[row][mid]<0 && arr[row][mid+1]>0)
{
return mid+1;
}
}
}
int main()
{
int ri,ci,sum;
ri=0; //rowindex
ci=0; //columnindex
sum=0;
for(int i=0; i<5; i++)
{
for(int j=0; j<5; j++)
{
cin>>arr[i][j];
}
}
while(ri<5)
{
if(arr[ri][ci]>=0)
{
ri++;
}
else if(arr[ri][ci]<0)
{
int p=func(ri);
sum+=p;
ri++;
}
}
printf("%d\n",sum);
}
I ran the code here http://ideone.com/PIlNd2
runtime O(xlogy) for a matrix of x rows and y columns
Correct me if i am wrong in time complexity or implementation of code
Does anyone have any better idea than this to improve Run-time complexity?
O(m+n) algorithm, where m and n are the dimensions of the array, working by sliding down the top of the negative portion, finding the last negative number in each row. This is most likely what Prashant was talking about in the comments:
int negativeCount(int m, int n, int **array) {
// array is a pointer to m pointers to n ints each.
int count = 0;
int j = n-1;
for (int i = 0, i < m; i++) {
// Find the last negative number in row i, starting from the index of
// the last negative number in row i-1 (or from n-1 when i==0).
while (j >= 0 && array[i][j] >= 0) {
j--;
}
if (j < 0) {
return count;
}
count += j+1;
}
return count;
}
We can't do better than worst-case O(m+n), but if you're expecting far fewer than m+n negative numbers, you may be able to get a better usual-case time.
Suppose you have an n by n array, where array[i][j] < 0 iff i < n-j. In that case, the only way the algorithm can tell that array[i][n-1-i] < 0 for any i is by looking at that cell. Thus, the algorithm has to look at at least n cells.
You are conducting a binary search. Whereby you divide n by 2 to find the midpoint then continue to divide, before returning a value. That looks like a binary search, even though you are dividing columns for each row. Therefore, you are performing O(log n). Or something like O(x log n/y).