Codechef practice question help needed - find trailing zeros in a factorial - c++

I have been working on this for 24 hours now, trying to optimize it. The question is how to find the number of trailing zeroes in factorial of a number in range of 10000000 and 10 million test cases in about 8 secs.
The code is as follows:
#include<iostream>
using namespace std;
int count5(int a){
int b=0;
for(int i=a;i>0;i=i/5){
if(i%15625==0){
b=b+6;
i=i/15625;
}
if(i%3125==0){
b=b+5;
i=i/3125;
}
if(i%625==0){
b=b+4;
i=i/625;
}
if(i%125==0){
b=b+3;
i=i/125;
}
if(i%25==0){
b=b+2;
i=i/25;
}
if(i%5==0){
b++;
}
else
break;
}
return b;
}
int main(){
int l;
int n=0;
cin>>l; //no of test cases taken as input
int *T = new int[l];
for(int i=0;i<l;i++)
cin>>T[i]; //nos taken as input for the same no of test cases
for(int i=0;i<l;i++){
n=0;
for(int j=5;j<=T[i];j=j+5){
n+=count5(j); //no of trailing zeroes calculted
}
cout<<n<<endl; //no for each trialing zero printed
}
delete []T;
}
Please help me by suggesting a new approach, or suggesting some modifications to this one.

Use the following theorem:
If p is a prime, then the highest
power of p which divides n! (n
factorial) is [n/p] + [n/p^2] +
[n/p^3] + ... + [n/p^k], where k is
the largest power of p <= n, and [x] is the integral part of x.
Reference: PlanetMath

The optimal solution runs in O(log N) time, where N is the number you want to find the zeroes for. Use this formula:
Zeroes(N!) = N / 5 + N / 25 + N / 125 + ... + N / 5^k, until a division becomes 0. You can read more on wikipedia.
So for example, in C this would be:
int Zeroes(int N)
{
int ret = 0;
while ( N )
{
ret += N / 5;
N /= 5;
}
return ret;
}
This will run in 8 secs on a sufficiently fast computer. You can probably speed it up by using lookup tables, although I'm not sure how much memory you have available.
Here's another suggestion: don't store the numbers, you don't need them! Calculate the number of zeroes for each number when you read it.
If this is for an online judge, in my experience online judges exaggerate time limits on problems, so you will have to resort to ugly hacks even if you have the right algorithm. One such ugly hack is to not use functions such as cin and scanf, but instead use fread to read a bunch of data at once in a char array, then parse that data (DON'T use sscanf or stringstreams though) and get the numbers out of it. Ugly, but a lot faster usually.

This question is from codechef.
http://www.codechef.com/problems/FCTRL
How about this solution:
#include <stdio.h>
int a[] = {5, 25, 125, 625, 3125, 15625, 78125, 390625, 1953125, 9765625, 48828125, 244140625};
int main()
{
int i, j, l, n, ret = 0, z;
scanf("%d", &z);
for(i = 0; i < z; i++)
{
ret = 0;
scanf("%d", &n);
for(j = 0; j < 12; j++)
{
l = n / a[j];
if(l <= 0)
break;
ret += l;
}
printf("%d\n", ret);
}
return 0;
}
Any optimizations???

Knows this is over 2 years old but here's my code for future reference:
#include <cmath>
#include <cstdio>
inline int read()
{
char temp;
int x=0;
temp=getchar_unlocked();
while(temp<48)temp=getchar_unlocked();
x+=(temp-'0');
temp=getchar_unlocked();
while(temp>=48)
{
x=x*10;
x+=(temp-'0');
temp=getchar_unlocked();
}
return x;
}
int main()
{
int T,x,z;
int pows[]={5,25,125,625,3125,15625,78125,390625,1953125,9765625,48828125,244140625};
T=read();
for(int i=0;i<T;i++)
{
x=read();
z=0;
for(int j=0;j<12 && pows[j]<=x;j++)
z+=x/pows[j];
printf("%d\n",z);
}
return 0;
}
It ran in 0.13s

Here is my accepted solution. Its score is 1.51s, 2.6M. Not the best, but maybe it can help you.
#include <iostream>
using namespace std;
void calculateTrailingZerosOfFactoriel(int testNumber)
{
int numberOfZeros = 0;
while (true)
{
testNumber = testNumber / 5;
if (testNumber > 0)
numberOfZeros += testNumber;
else
break;
}
cout << numberOfZeros << endl;
}
int main()
{
//cout << "Enter number of tests: " << endl;
int t;
cin >> t;
for (int i = 0; i < t; i++)
{
int testNumber;
cin >> testNumber;
calculateTrailingZerosOfFactoriel(testNumber);
}
return 0;
}

#include <cstdio>
int main(void) {
long long int t, n, s, i, j;
scanf("%lld", &t);
while (t--) {
i=1; s=0; j=5;
scanf("%lld", &n);
while (i != 0) {
i = n / j;
s = s + i * (2*j + (i-1) * j) / 2;
j = j * 5;
}
printf("%lld\n", s);
}
return 0;
}

You clearly already know the correct algorithm. The bottleneck in your code is the use of cin/cout. When dealing with very large input, cin is extremely slow compared to scanf.
scanf is also slower than direct methods of reading input such as fread, but using scanf is sufficient for almost all problems on online judges.
This is detailed in the Codechef FAQ, which is probably worth reading first ;)

Related

Different Results for int and long long

So, I was doing a question that asked us to divide an array into two parts such that the difference between the sum of elements of both of the parts shall be minimum.
Say A = [3 2 7 4 1]. So, minimum difference is generated when [2 3 4] and [7 1] are the two parts, i.e. difference = (2+3+4)-(7+1) = 1.
My approach was pretty naive, which basically computed all different subsets of the given array, and calculate the absolute difference with its complementary array, and report the minimum of these values.
When I used int my program it gave the correct answers for all but two test cases. In these test cases, the inputs were exceeding the limits of int. So, I changed it to long long, but this gave very weird results. It even started giving wrong results for the previously correct results.
CORRECT OUTPUT GIVING CODE (using int):
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
int min_diff = INT_MAX;
void subsetGen(vector <int> &curr,vector <int> &v, int n, int index, int sum)
{
if (!curr.empty())
{
int sum_1 = accumulate(curr.begin(), curr.end(), 0);
int diff = abs(2*sum_1 - sum);
min_diff = (diff<min_diff) ? diff : min_diff;
}
for (int i = index; i < v.size(); i++)
{
curr.push_back(v[i]);
subsetGen (curr, v, n, i+1, sum);
curr.pop_back(); // Backtracking
}
return;
}
int main()
{
int n, sum = 0;
cin >> n;
vector <int> v (n, 0);
for (int i=0; i<n; i++)
{
cin >> v[i];
sum += v[i];
}
vector <int> curr;
subsetGen(curr,v,n,0,sum);
cout << min_diff;
return 0;
}
INCORRECT OUTPUT GIVING CODE (using long long):
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
ll min_diff = LLONG_MAX;
void subsetGen(vector <ll> &curr,vector <ll> &v, int n, int index, ll sum)
{
if (!curr.empty())
{
ll sum_1 = accumulate(curr.begin(), curr.end(), 0);
ll diff = abs(2*sum_1 - sum);
min_diff = (diff<min_diff) ? diff : min_diff;
}
for (int i = index; i < v.size(); i++)
{
curr.push_back(v[i]);
subsetGen (curr, v, n, i+1, sum);
curr.pop_back(); // Backtracking
}
return;
}
int main()
{
int n;
ll sum = 0;
cin >> n;
vector <ll> v (n, 0);
for (int i=0; i<n; i++)
{
cin >> v[i];
sum += v[i];
}
vector <ll> curr;
subsetGen(curr,v,n,0,sum);
cout << min_diff;
return 0;
}
This was the Input I was checking for:
20
452747515 202201476 845758891 733204504 327861300 368456549 64252070 494676885 21095634 611030397 913689714 849191653 173901982 954566440 40404105 228316310 210730656 631709598 847867437 85805975
The correct answer is: 4881 (which the program using int gave)
But using long long is giving me: 4762526359 (which is the wrong answer).
I tested these code in online compilers to see if this was a problem with only my system, but encountered the same problem.

Find largest mode in huge data set without timing out

Description
In statistics, there is a measure of the distribution called the mode. The mode is the data that appears the most in a data set. A data set may have more than one mode, that is, when there is more than one data with the same number of occurrences.
Mr. Dengklek gives you N integers. Find the greatest mode of the numbers.
Input Format
The first line contains an integer N. The next line contains N integers.
Output Format
A row contains an integer which is the largest mode.
Input Example
6
1 3 2 4 1 4
Example Output
4
Limits
1 ≤ N ≤100,000
1≤(every integer on the second line)≤1000
#include <iostream>
#include <string>
using namespace std;
#define ll long long
int main() {
unsigned int N;
while(true){
cin >> N;
if(N > 0 && N <= 1000){
break;
}
}
int arr[N];
int input;
for (int k = 0; k < N; k++)
{
cin >> input;
if(input > 0 && input <=1000){
arr[k] = input;
}
else{
k -= 1;
}
}
int number;
int mode;
int position;
int count = 0;
int countMode = 1;
for (int i = 0; i < N; i++)
{
number = arr[i];
for (int j = 0; j < N; j++)
{
if(arr[j] == number){
++count;
}
}
if(count > countMode){
countMode = count;
mode = arr[i];
position = i;
}
else if(count == countMode){
if(arr[i] > arr[position]){
mode = arr[i];
position = i;
}
}
count = 0;
}
cout << mode << endl;
return 0;
}
I got a "RTE" (run time error) and 70 pts.
Here is the code which I got 80 pts but got "TLE" (time limit exceeded):
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int main() {
unsigned int N;
while(true){
cin >> N;
if(N > 0 && N <= 100000){
break;
}
}
int arr[N];
int input;
for (int k = 0; k < N; k++)
{
cin >> input;
if(input > 0 && input <=1000){
arr[k] = input;
}
else{
k -= 1;
}
}
int number;
vector<int> mode;
int count = 0;
int countMode = 1;
for (int i = 0; i < N; i++)
{
number = arr[i];
for (int j = 0; j < N; j++)
{
if(arr[j] == number){
++count;
}
}
if(count > countMode){
countMode = count;
mode.clear();
mode.push_back(arr[i]);
}
else if(count == countMode){
mode.push_back(arr[i]);
}
count = 0;
}
sort(mode.begin(), mode.end(), greater<int>());
cout << mode.front() << endl;
return 0;
}
How can I accelerate the program?
As already noted, the algorithm implemented in both of the posted snippets has O(N2) time complexity, while there exists an O(N) alternative.
You can also take advantage of some of the algorithms in the Standard Library, like std::max_element, which returns an
iterator to the greatest element in the range [first, last). If several elements in the range are equivalent to the greatest element, returns the iterator to the first such element.
#include <algorithm>
#include <array>
#include <iostream>
int main()
{
constexpr long max_N{ 100'000L };
long N;
if ( !(std::cin >> N) or N < 1 or N > max_N )
{
std::cerr << "Error: Unable to read a valid N.\n";
return 1;
}
constexpr long max_value{ 1'000L };
std::array<long, max_value> counts{};
for (long k = 0; k < N; ++k)
{
long value;
if ( !(std::cin >> value) or value < 1 or value > max_value )
{
std::cerr << "Error: Unable to read value " << k + 1 << ".\n";
return 1;
}
++counts[value - 1];
}
auto const it_max_mode{ std::max_element(counts.crbegin(), counts.crend()) };
// If we start from the last... ^^ ^^
std::cout << std::distance(it_max_mode, counts.crend()) << '\n';
// The first is also the greatest.
return 0;
}
Compiler Explorer demo
I got a "RTE" (run time error)
Consider this fragment of the first snippet:
int number;
int mode;
int position; // <--- Note that it's uninitialized
int count = 0;
int countMode = 1;
for (int i = 0; i < N; i++)
{
number = arr[i];
// [...] Evaluate count.
if(count > countMode){
countMode = count;
mode = arr[i];
position = i; // <--- Here it's assigned a value, but...
}
else if(count == countMode){ // If this happens first...
if(arr[i] > arr[position]){
// ^^^^^^^^^^^^^ Position may be indeterminate, here
mode = arr[i];
position = i;
}
}
count = 0;
}
Finally, some resources worth reading:
Why is “using namespace std;” considered bad practice?
Why should I not #include <bits/stdc++.h>?
Using preprocessing directive #define for long long
Why aren't variable-length arrays part of the C++ standard?
You're overcomplicating things. Competitive programming is a weird beast were solutions assume limited resources, whaky amount of input data. Often those tasks are balanced that way that they require use of constant time alternate algorithms, summ on set dynamic programming. Size of code is often taken in consideration. So it's combination of math science and dirty programming tricks. It's a game for experts, "brain porn" if you allow me to call it so: it's wrong, it's enjoyable and you're using your brain. It has little in common with production software developing.
You know that there can be only 1000 different values, but there are huge number or repeated instances. All that you need is to find the largest one. What's the worst case of finding maximum value in array of 1000? O(1000) and you check one at the time. And you already have to have a loop on N to input those values.
Here is an example of dirty competitive code (no input sanitation at all) to solve this problem:
#include <bits/stdc++.h>
using namespace std;
using in = unsigned short;
array<int, 1001> modes;
in biggest;
int big_m;
int N;
int main()
{
cin >> N;
in val;
while(N --> 0){
cin >> val;
if(val < 1001) {
modes[val]++;
}
else
continue;
if( modes[val] == big_m) {
if( val > biggest )
biggest = val;
}
else
if( modes[val] > big_m) {
biggest = val;
big_m = modes[val];
}
}
cout << biggest;
return 0;
}
No for loops if you don't need them, minimalistic ids, minimalistic data to store. Avoid dynamic creation and minimize automatic creation of objects if possible, those add execution time. Static objects are created during compilation and are materialized when your executable is loaded.
modes is an array of our counters, biggest stores largest value of int for given maximum mode, big_m is current maximum value in modes. As they are global variables, they are initialized statically.
PS. NB. The provided example is an instance of stereotype and I don't guarantee it's 100% fit for that particular judge or closed test cases it uses. Some judges use tainted input and some other things that complicate life of challengers, there is always a factor of unknown. E.g. this example would faithfully output "0" if judge would offer that among input values even if value isn't in range.

(C++) Generate first p*n perfect square numbers in an array (p and n inputted from the keyboard)

I input p and n (int type) numbers from my keyboard, I want to generate the first p*n square numbers into the array pp[99]. Here's my code:
#include <iostream>
#include <math.h>
using namespace std;
int main()
{
int i, j, n, p, pp[19];
cout<<"n="; cin>>n;
cout<<"p="; cin>>p;
i=n*p;
j=-1;
while(i!=0)
{
if(sqrt(i)==(float)sqrt(i))
{
j++;
pp[j]=i;
}
i--;
}
for(i=0; i<n*p; i++)
cout<<pp[i]<<" ";
return 0;
}
But I am encountering the following problem: If I for example I enter p=3 and n=3, it will only show me the first 3 square numbers instead of 9, the rest 6 being zeros. Now I know why this happens, just not sure how to fix it (it's checking the first n * p natural numbers and seeing which are squares, not the first n*p squares).
If I take the i-- and add it in the if{ } statement then the algorithm will never end, once it reaches a non-square number (which will be instant unless the first one it checks is a perfect square) the algorithm will stop succeeding in iteration and will be blocked checking the same number an infinite amount of times.
Any way to fix this?
Instead of searching for them, generate them.
int square(int x)
{
return x * x;
}
int main()
{
int n = 0;
int p = 0;
std::cin >> n >> p;
int limit = n * p;
int squares[99] = {};
for (int i = 0; i < limit; i++)
{
squares[i] = square(i+1);
}
for (int i = 0; i < limit; i++)
{
std::cout << squares[i] << ' ';
}
}

C++ Counting inversions in array, Fatal Signal 11 (BIT)

I was given this challenge in a programming "class". Eventually I decided to go for the "Binary Indexed Trees" solution, as data structures are a thing I'd like to know more about. Implementing BIT was somewhat straight forward, things after that - not so much. I ran into "Fatal Signal 11" when uploading the solution to the server, which, from what I've read, is somewhat similar to a Null pointer exception. Couldn't figure out the problem, decided to check out other solutions with BIT but stumbled upon the same problem.
#include<iostream>
using namespace std;
/* <BLACK MAGIC COPIED FROM geeksforgeeks.org> */
int getSum(int BITree[], int index){
int sum = 0;
while (index > 0){
sum += BITree[index];
index -= index & (-index);
}
return sum;
}
void updateBIT(int BITree[], int n, int index, int val){
while (index <= n){
BITree[index] += val;
index += index & (-index);
}
}
/* <BLACK MAGIC COPIED FROM geeksforgeeks.org> */
int Count(int arr[], int x){
int sum = 0;
int biggest = 0;
for (int i=0; i<x; i++) {
if (biggest < arr[i]) biggest = arr[i];
}
int bit[biggest+1];
for (int i=1; i<=biggest; i++) bit[i] = 0;
for (int i=x-1; i>=0; i--)
{
sum += getSum(bit, arr[i]-1);
updateBIT(bit, biggest, arr[i], 1);
}
return sum;
}
int main(){
int x;
cin >> x;
int *arr = new int[x];
for (int temp = 0; temp < x; temp++) cin >> arr[temp];
/*sizeof(arr) / sizeof(arr[0]); <-- someone suggested this,
but it doesn't change anything from what I can tell*/
cout << Count(arr,x);
delete [] arr;
return 0;
}
I am quite stumped on this. It could be just some simple thing I'm missing, but I really don't know. Any help is much appreciated!
You have condition that every number lies between 1 and 1018. So, your biggest number can be 1018. This is too much for the following line:
int bit[biggest+1];

Summing Large Numbers

I have being doing some problems on the Project Euler website and have come across a problem. The Question asks,"Work out the first ten digits of the sum of the following one-hundred 50-digit numbers." I am guessing there is some mathematical way to solve this but I was just wondering how numbers this big are summed? I store the number as a string and convert each digit to a long but the number is so large that the sum does not work.
Is there a way to hold very large numbers as a variable (that is not a string)? I do not want the code to the problem as I want to solve that for myself.
I was just wondering how numbers this big are summed?
You can use an array:
long LargeNumber[5] = { < first_10_digits>, < next_10_digits>....< last_10_digits> };
Now you can calculate the sum of 2 large numbers:
long tempSum = 0;
int carry = 0;
long sum[5] = {0,0,0,0,0};
for(int i = 4; i >= 0; i--)
{
tempSum = largeNum1[i] + largeNum2[i] + carry; //sum of 10 digits
if( i == 0)
sum[i] = tempSum; //No carry in case of most significant digit
else
sum[i] = tempSum % 1000000000; //Extra digits to be 'carried over'
carry = tempSum/1000000000;
}
for( int i = 0; i < 5; i++ )
cout<<setw(10)<<setfill('0')<<sum[i]<<"\n"; //Pad with '0' on the left if needed
Is there a way to hold very large numbers as a variable (that is not a
string)?
There's no primitive for this, you can use any data structure (arrays/queues/linkedlist) and handle it suitably
I am guessing there is some mathematical way to solve this
Of course! But,
I do not want the code to the problem as I want to solve that for myself.
You may store the digits in an array. To save space and increase performance in the operations, store the digits of the number in base 10^9. so a number
182983198432847829347802092190
will be represented as the following in the array
arr[0]=2092190
arr[1]=78293478 arr[2]=19843284 arr[3]=182983
just for the sake of clarity, the number is represented as summation of arr[i]*(10^9i)
now start with i=0 and start adding the numbers the way you learnt as a kid.
I have done in java, Here I am taking to numbers N1 and N2, And I have create an array of size 1000. Lets take an example How to solve this, N1=12, N2=1234. For N1=12, temp=N1%10=2, Now add this digit with digit N2 from right to Left and store the result into array starting from i=0, similarly for rest digit of N1. The array will store the result but in reverse order. Have a looking on this link. Please check this link http://ideone.com/V5knEd
import java.util.*;
import java.lang.*;
import java.io.*;
/* Name of the class has to be "Main" only if the class is public. */
class Ideone
{
public static void main (String[] args) throws java.lang.Exception {
Scanner scan=new Scanner(System.in);
int A=scan.nextInt();
int B=scan.nextInt();
int [] array=new int[1000];
Arrays.fill(array,0);
int size=add(A,B,array);
for(int i=size-1;i>=0;i--){
System.out.print(array[i]);
}
}
public static int add(int A, int B, int [] array){
int carry=0;
int i=0;
while(A>0 || B>0){
int sum=A%10+B%10+carry+array[i];
array[i]=sum%10;
carry=sum/10;
A=A/10;
B=B/10;
i++;
}
while(carry>0){
array[i]=array[i]+carry%10;
carry=carry/10;
i++;
}
return i;
}
}
#include<iostream>
#include<fstream>
#include<sstream>
using namespace std;
struct grid{
int num[50];
};
int main()
{
struct grid obj[100];
char ch;
ifstream myfile ("numbers.txt");
if (myfile.is_open())
{
for(int r=0; r<100; r++)
{
for(int c=0; c<50; c++)
{
myfile >> ch;
obj[r].num[c] = ch - '0';
}
}
myfile.close();
int result[50],temp_sum = 0;
for (int c = 49; c>=0; c--)
{
for (int r=0; r<100; r++)
{
temp_sum += obj[r].num[c];
}
result[c] = temp_sum%10;
temp_sum = temp_sum/10;
}
string temp;
ostringstream convert;
convert << temp_sum;
temp = convert.str();
cout << temp_sum;
for(unsigned int count = 0; count < (10 - temp.length()); count++)
{
cout << result[count];
}
cout << endl;
}
return 0;
}
This the best way for your time and memory size :D
#include <iostream >
#include <climits >
using namespace std;
int main()
{
unsigned long long z;
cin >>z;
z=z*(z+1)/2;
C out << z;
return 0;
}