Some time ago I ask in codereview.stackexchange a review for one of my problems. I din't get a sufficient answer and many people told me to post a question here just to get more answers and solutions. My problem is the follwoing.
Giving a dynamic array, we want to pass the array elements from a
file. The first number in the file N gives us the array length. They
follow N numbers, the actual elements of the array.
Three brothers are going to work in the shop of their father for a time. The >shop is doing well and every day generates profit which the
three brothers may provide. The brothers agreed that they would divide
the total time in three successive parts, not necessarily equal
duration, and that each one will be working in the shop during one of
these parts and collects the corresponding profit on his behalf. But
they want to make a deal fairly, so that one received from three more
profit someone else. Specifically, they want to minimize the profit
the most favored of the three will receive.
Now I created a solution with O(n^2) complexity but I want to know if someone has any other idea to solve the problem with linear complexity.
Lets assume we have the follwoing input :
1 1 8 1 1 3 4 9 5 2
The output is 15.
A=1+1+8+1+1+3 , B=4+9=13 , C=5+2=7
Remenber I want linear complexity. If someone believe it's just a homework to be done and I boring then he has no place here. I just want to know if someone has any idea how to solve the problem in C.
My try was the following:
#include <stdio.h>
#include <limits.h>
#define max(A,B,C) A > (B > C ? B : C) ? A : (B > C ? B : C)
#define N 10
int main()
{
int e[N] = {1, 1, 8, 1, 1, 3, 4, 9, 5, 2 };
int i=0;
int j = N-1;
int A = e[i];
int C = e[j];
int B = 0;
int x, AL, CR, BL, BR, m, mp = INT_MAX, L, R;
for(x = i+1 ; x < j; x++) B+=e[x];
m = max(A,B,C);
printf("A=%d B=%d C=%d\n", A, B, C);
while(m < mp)
{
AL = A+e[i+1];
CR = C+e[j-1];
BL = B-e[i+1];
BR = B-e[j-1];
L = max(AL,BL,C);
R = max(A,BR,CR);
if(L<R)
{
A=AL;
B=BL;
i++;
}
else
{
C=CR;
B=BR;
j--;
}
mp = m;
m = max(A,B,C);
printf("A=%d B=%d C=%d MAX=%d\n", A, B, C, m);
}
printf("%d", mp);
return 0;
}
I don't want someone to base in the above code cause it gives wrong outputs in 90% of the most inputs.
Related
I'm new to competitive programming and I participated in Codeforces #653 in which I spent the whole time solving this problem and did not submit any code because of exceeded time limits or wrong answer for test cases.
I wanted to solve this problem - https://codeforces.com/contest/1374/problem/A
You are given three integers x,y and n. Your task is to find the maximum integer k such that 0 ≤k≤ n that k mod x=y, where mod is modulo operation. Many programming languages use percent operator % to implement it.
In other words, with given x,y and n you need to find the maximum possible integer from 0 to n that has the remainder y modulo x
You have to answer t independent test cases. It is guaranteed that such k exists for each test case.
I wrote this following code:
#include <stdio.h>
int main(){
int i,t,j,k=0;
int x[60000],y[60000],n[60000],prev[60000];
scanf("%d",&t);
for(i=0; i<t; i++){
scanf("%d %d %d",&x[i],&y[i],&n[i]);
}
for(i=0; i<t; i++){
for(j=0, k=0; j<n[i]; j++ , k++){
if(j%x[i]==y[i]){
prev[i]=k;
}
}
}
for(i=0; i<t; i++){
printf("%d",prev[i]);
printf("\n");
}
return 0;
}
Everything was working fine but for some test cases I'm getting different answers.
This was the expected output
12339
0
15
54306
999999995
185
999999998
and my output was this:
12339
0
5
54306
999999995
185
999999998
I did not understand why I got 5 instead of 15 keeping all the other outputs correct and also could anyone please help me to optimize the code, its taking too long to compile for large inputs.
For the 1st part of your question, why the answer is wrong - has been answered nicely by others already. For the 2nd part about efficiency, the solution doesn't need any extra loop except the loop for iterating over the test case.
The solution could be as easy as this:
k = n - ((n - y) % x)
For example:x = 7, y = 5, n = 12345. Then,
k = 12345 - ((12345 - 5) % 7)
= 12339
This small piece of code could get you accepted:
#include <stdio.h>
int main()
{
int t, x, y, n;
scanf("%d", &t);
while (t > 0) {
scanf("%d %d %d", &x, &y, &n);
printf("%d\n", n - ((n - y) % x));
t--;
}
}
The reason you were getting TLE was because your code was taking too long. As I can see n could be upto 10^9 and so a O(N) solution would easily time-out at such constraints. Add to that, the fact that your code would be given upto 5*10^4 test cases. So, for your code to work, it should be much faster than O(N) time complexity. I have explained a better approach below which would satisfy the given constraints.
Optimised Approach :
For each test case, we are given x, y, n. And we have to find the largest number( let's say ans) between 0 to n such that ans%x = y.
Let's first find the remainder when we divide n by x. So, remainder = n%x. Now, if the remainder >= y, this means that we would have to reduce n such that it will leave a smaller remainder that is => a remainder equal to y. For this, we can simply reduce n by (remainder - y) amount.
Example :
For better understanding, lets see an example where
x = 10, y = 5, n = 16.
In this case remainder = n%x = 6. Now remainder > y, so we can just reduce our n by (remainder - y), that is n now becomes 15. We see that 15%x = y and so that's our answer.
The other case we might get is remainder < y. In this case, we have to increase the remainder. But we can't increase n (since it is the upper limit). So, what we can instead do is subtract x from n. The remainder will still be same. But now we are allowed to increase n by some amount which results in remainder to be y. For that we simply increase n by an amount y - remainder, so that new remainder will be equal to y.
Example :
Let's consider example where
x = 10, y = 5 and n = 24
Here, remainder = n%x = 4. So remainder < y. We subtract x from n, so n becomes 14 but still n%x = 4, so remainder remains same. But, we now have the advantage that we can increase x so that remainder would be equal to y. Since our remainder is 1 less than required (y), we increase n by 1 (or y - remainder = 1). Thus, we have the answer = 15.
This approach has time complexity of O(1) which is far better than O(N) approach. I hope that you got the idea of the approach I was trying to explain. Below is the pseudocode for same -
Pseudocode
remainder = n%x
if (remainder >= y) // Case 1
return n - ( remainder - y ) as the answer
else // Case 2
return ( n - x ) + ( y - remainder ) as the answer
Hope this helps !
The first part of this answer will explain what's wrong in your logic. The second part will contain a plot twist.
How to get the correct answer
As you have correctly been told in comments by #ErichKitzmueller your inner loop searches k values in the range [0-n[. In other words, if you are not familiar to my mathematical notation, you are not even considering the value n that is not included in your loop search, as you do for(j=0, k=0; j<n[i]; j++ , k++).
For the record, [0-n[ means "range from to 0 to n including 0 and not including n.
If you have to search the maximum value satisfying a given requirement... why starting counting from 0? You just need starting from the right limit of the range and loop backwards. The first k you will find satisfying the condition will be your output, so you'll just need to save it and exit the inner loop.
No need to find ALL the numbers satisfying the condition and overwrite them until the last is found (as you do).
The main loop of your solution would become something like that:
for(i=0; i<t; i++){
int found = 0;
for(k=n[i]; k>=0 && found==0; k--)
{
if( ( k % x[i] ) == y[i] )
{
prev[i] = k;
found = 1;
}
}
}
The plot twist (the REAL solution)
The previous solution will lead to correct answers... anyway it will be rejected as it exceeds the time limit.
Actually, all these competitive coding problems are all based on asking for a problem that in some way is simpler than it looks. In other words, it's always possible to find a way (usually after a mathematical analysis) that have a lower computational complexity than the one of the first solution that comes to your mind.
In this case we have to think:
What is the reminder of a division? y = k%x = k - x*int(k/x)
When has this expression its max? When k=n. So y = k - x*int(n/x)
So k = x*int(n/x) + y
Finally, we want make sure that this number is lower than n. If it is, we subtract x
The code becomes something like this:
#include <stdio.h>
int main(){
int i, t;
int x[60000],y[60000],n[60000],k[60000];
scanf("%d",&t);
for(i=0; i<t; i++){
scanf("%d %d %d",&x[i],&y[i],&n[i]);
}
for(i=0; i<t; i++){
int div = n[i] / x[i]; // Since div is an integer, only the integer part of the division is stored to div
k[i] = x[i] * div + y[i];
if( k[i] > n[i] )
k[i] -= x[i];
}
for(i=0; i<t; i++){
printf("%d", k[i]);
printf("\n");
}
return 0;
}
I've tested the solution on Codeforce, and it has been accepted.
the following proposed code:
cleanly compiles
performs the desired functionality
is very quick (could be made quicker via different I/O functions)
and now, the proposed code:
#include <stdio.h>
int main()
{
int x;
int y;
int n;
size_t t;
scanf("%zu",&t);
for( ; t; t-- )
{
scanf( "%d %d %d", &x, &y, &n );
printf( "%d\n", n - ((n - y) % x) );
}
return 0;
}
I have a programming assignment that goes like this:
You are given three numbers a, b, and c. (1 ≤ а, b, c ≤ 10^18)
Each time you have two choises, either add b to a (a+=b), or add a to b (b+=a). Write a program that will print out YES or NO depending on whether you can get to c by adding a and b to each other.
I've tried solving this problem using recursion that branches to two branches every time where one branch stores a+b, b and the other branch stores a, b+a. In every recursive call, the function checks the values of a and b, and if they are equal to c the search stops and the function prints YES. The recursion stops when either a or b have a value greater than c.
Here's how the branching works:
And here's the code in C:
#include <stdio.h>
#include <stdlib.h>
void tree(long long int a, long long int b, long long int c){
if(a==c || b==c){
printf("YES");
exit(0);
}
else if(a<c && b<c){
tree(a, b+a, c);
tree(a+b, b, c);
}
}
int main(){
long long int a, b, c;
scanf("%I64d", &a);
scanf("%I64d", &b);
scanf("%I64d", &c);
tree(a, b, c);
printf("NO");
return 0;
}
Now, this program works for small numbers, but since a b and c can be any 64-bit number, the tree can branch itself a few billion times, and the program runs out of memory and crashes.
My question is: Is there any way i can improve my code, or use any other way (other then recursion) to solve this?
OK I'll have to admit that this turned out to be a fascinating question. I really thought that there should be a quick way of finding out the answer but the more I looked at the problem, the more complex it became. For example, if you zigzag down the tree, alternating a+=b with b+=a, you are essentially creating the fibonacci sequence (imagine a=2 and b=3 to start with). Which means that if you could find the answer quickly, you could somehow use a similar program to answer "is c a fibonacci number"?
So I never came up with anything better than searching the binary tree. But I did come up with a way to search the binary tree without running out of memory. The key trick in my algorithm is that at every node you need to search two child nodes. But you don't need to recurse down both paths. You only need to recurse down one path, and if that fails, you can iterate to the other child. When recursing, you should always pick the path where the smaller number changes. This guarantees that you are doubling the minimum element on each recursion level, which guarantees that you will only recurse 64 times max before your minimum element will exceed 2^64.
So I wrote the program and ran it, and it worked just fine. That is until I entered a very large number for c. At that point, it didn't finish. I found from testing that the algorithm appears to have an O(N^2) running time, where N = c. Here are some sample running times (all on a desktop running 64-bit Windows).
Inputs Time in minutes
------ ---------------
a=2 b=3 c=10000000000 (10^10): 0:20
a=2 b=3 c=100000000000 (10^11): 13:42
a=2 b=3 c=100000000001 : 2:21 (randomly found the answer quickly)
a=2 b=3 c=100000000002 : 16:36
a=150 b=207 c=10000000 (10^7) : 0:08 (no solution)
a=150 b=207 c=20000000 : 0:31 (no solution)
a=150 b=207 c=40000000 : 2:05 (no solution)
a=150 b=207 c=100000000 (10^8) : 12:48 (no solution)
Here is my code:
// Given three numbers: a, b, c.
//
// At each step, either do: a += b, or b += a.
// Can you make either a or b equal to c?
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
static int solve(uint64_t a, uint64_t b, uint64_t c);
int main(int argc, char *argv[])
{
uint64_t a = 0, b = 0, c = 0;
if (argc < 4) {
printf("Usage: %s a b c\n", argv[0]);
exit(0);
}
a = strtoull(argv[1], NULL, 0);
b = strtoull(argv[2], NULL, 0);
c = strtoull(argv[3], NULL, 0);
// Note, by checking to see if a or b are solutions here, solve() can
// be made simpler by only checking a + b == c. That speeds up solve().
if (a == c || b == c || solve(a, b, c))
printf("There is a solution\n");
else
printf("There is NO solution\n");
return 0;
}
int solve(uint64_t a, uint64_t b, uint64_t c)
{
do {
uint64_t sum = a + b;
// Check for past solution.
if (sum > c)
return 0;
// Check for solution.
if (sum == c)
return 1;
// The algorithm is to search both branches (a += b and b += a).
// But first we search the branch where add the higher number to the
// lower number, because that branch will be guaranteed to double the
// lower number, meaning we will not recurse more than 64 times. Then
// if that doesn't work out, we iterate to the other branch.
if (a < b) {
// Try a += b recursively.
if (solve(sum, b, c))
return 1;
// Failing that, try b += a.
b = sum;
} else {
// Try b += a recursively.
if (solve(a, sum, c))
return 1;
// Failing that, try a += b.
a = sum;
}
} while(1);
}
Edit: I optimized the above program by removing recursion, reordering the arguments so that a is always less than b at every step, and some more tricks. It runs about 50% faster than before. You can find the optimized program here.
Based on comment from #Oliver Charlesworth, this is an iterative not recursive solution so it won't solve the homework. But it's pretty simple, I step through b because it is larger than a (although that is not entirely clear from the OP) hence fewer iterations required.
#include <stdio.h>
int main(){
unsigned long long int a, b, c, bb;
scanf("%I64u", &a);
scanf("%I64u", &b);
scanf("%I64u", &c);
if (a >= 1 && a < b && b < c) {
for (bb=b; bb<c; bb+=b) {
if ((c - bb) % a == 0) {
printf ("YES\n");
return 0;
}
}
}
printf("NO\n");
return 0;
}
I have tried to solve Project Euler problem 2 by a for loop. I'm new to c programming and I cannot seem to get the algorithm right.
3524579
The for loop is suppose to look at for the 32 fibonacci which is less than 4000000. Then I have defined the fibonacci function and after than I want to add the even fibonacci numbers by the second for loop.
I get 3524579, can anyone help me with what I'm doing wrong?
/* Edited:
Ok, I rewrote the code using your tips. I do not understand why this does not work. I tried to write each steps down on paper:
The predicate is evaluated b mod 2 == 0, so the following happends:
sum = 2 + 0
a = b -> a == 2
b = sum -> b == 2
These steps iterate until the value 4mill. Can someone see what I fail to not see :p?*/
New edited version: I finally it work using a for-loop. Just wondering if there was a prettier way to do it using for-loop maybe.
#include <stdio.h>
int main() {
int a = 0;
int b = 1;
int result = 0;
int sum = 0;
for(;;){
if(!(b < 4000000)) break;
if(b % 2 == 0)
result = result + b;
sum = a + b;
a = b;
b = sum;
printf("%d\n", result);
}
}
A couple things:
Notice that your answer is equal to the 31st fib number + 1. This means you are replacing your total with new values on every iteration instead of keeping a running total.
Consider looping until the current fib number gets > 4M instead of figuring out beforehand that there are 32 fib numbers you need to look at.
A simple program I wrote in C takes upwards of half an hour to run. I am surprised that C would take so long to run, because from what I can find on the internet C ( aside from C++ or Java ) is one of the faster languages.
// this is a program to find the first triangular number that is divisible by 500 factors
int main()
{
int a; // for triangular num loop
int b = 1; // limit for triangular num (1+2+3+......+b)
int c; // factor counter
int d; // divisor
int e = 1; // ends loop
long long int t = 0; // triangular number in use
while( e != 0 )
{
c = 0;
// create triangular number t
t = t + b;
b++;
// printf("%lld\n", t); // in case you want to see where it's at
// counts factors
for( d = 1 ; d != t ; d++ )
{
if( t % d == 0 )
{
c++;
}
}
// test to see if condition is met
if( c > 500 )
{
break;
}
}
printf("%lld is the first triangular number with more than 500 factors\n", t);
getchar();
return 0;
}
Granted the program runs through a lot of data, but none of it is ever saved, just tested and passed over.
I am using the Tiny C Compiler on Windows 8.
Is there a reason this runs so slowly? What would be a faster way of achieving the same result?
Thank you!
You're iterating over a ton of numbers you don't need to. By definition, a positive factor is any whole number that can be multiplied by another to obtain the desired product.
Ex: 12 = 1*12, 2*6, and 3*4
The order of multiplication are NOT considered when deciding factors. In other words,
Ex: 12 = 2*6 = 6*2
The order doesn't matter. 2 and 6 are factors once.
The square root is the one singleton that will come out of a factoring of a product that stands alone. All others are in pairs, and I hope that is clear. Given that, you can significantly speed up your code by doing the following:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
// this is a program to find the first triangular number that is divisible by 500 factors
int main()
{
int c = 0; // factor counter
long long int b = 0; // limit for triangular num (1+2+3+......+b)
long long int d; // divisor
long long int t = 0; // triangular number in use
long long int r = 0; // root of current test number
while (c <= 500)
{
c = 0;
// next triangular number
t += ++b;
// get closest root.
r = floor(sqrt(t));
// counts factors
for( d = 1 ; d < r; ++d )
{
if( t % d == 0 )
c += 2; // add the factor *pair* (there are two)
}
if (t % r == 0) // add the square root if it is applicable.
++c;
}
printf("%lld is the first triangular number with more than 500 factors\n", t);
return 0;
}
Running this on IDEOne.com takes less than two seconds to come up with the following:
Output
76576500 is the first triangular number with more than 500 factors
I hope this helps. (and I think that is the correct answer). There are certainly more efficient ways of doing this (see here for some spoilers if you're interested), but going with your code idea and seeing how far we could take it was the goal of this answer.
Finally, this finds the first number with MORE than 500 factors (i.e. 501 or more) as per your output message. Your comment at the top of the file indicates you're looking for the first number with 500-or-more, which does not match up with your output message.
Without any math analysis:
...
do
{
c = 0;
t += b;
b++;
for (d = 1; d < t; ++d)
{
if (!(t % d))
{
c++;
}
}
} while (c <= 500);
...
You are implementing an O(n^2) algorithm. It would be surprising if the code took less than a half an hour.
Refer to your computer science textbook for a better method compared to this brute force method of: check 1, 1 + 2, 1 + 2 + 3, etc.
You might be able to shorten the inner for loop. Does it really need to check all the way up to t for factors that divide the triangular number. For example, can 10 be evenly divisible by any number greater than 5? or 100 by any number greater than 50?
Thus, given a number N, what is the largest number that can evenly divide N?
Keep reading/researching this problem.
Also, as other people have mentioned, the outer loop could be simply coded as:
while (1)
{
// etc.
}
So, no need need to declare e, or a? Note, this doesn't affect the length of time, but your coding style indicates you are still learning and thus a reviewer would question everything your code does!!
You are doing some unnecessary operations, and I think those instructions are not at all required if we can check that simply.
first :
while(e!=0)
as you declared e=1, if you put only 1 in loop it will work. You are not updating value of e anywhere.
Change that and check whether it works fine or not.
One of the beautiful things about triangle numbers, is that if you have a triangle number, with a simple addition operation, you can have the next one.
we have been asked to write a program to generate fibonacci series as our homework.
so i wrote a program that generates the first n fibonacci numbers .here is my frist code that dosent work properly
# include <stdio.h>
void main()
{
int a = -1, b = 1, c = 0, i, n, sum = 0 ;
printf("Enter the limit : ") ;
scanf("%d", &n) ;
printf("\nThefibonacci series is : \n\n") ;
for(i = 1 ; i <= n ; i++)
{
c = a + b ;
printf("%d \t", c) ;
b=c;
a=b;
}
}
so i tried various combinations and i found out that my code would work well if i interchanged the 12th and 13th lines. i.e
# include <stdio.h>
void main()
{
int a = -1, b = 1, c = 0, i, n, sum = 0 ;
printf("Enter the limit : ") ;
scanf("%d", &n) ;
printf("\nThefibonacci series is : \n\n") ;
for(i = 1 ; i <= n ; i++)
{
c = a + b ;
printf("%d \t", c) ;
a=b;
b=c;
}
}
It is the same logic right.
why does the first code give me wrong output?
what are segmentation faults?(my compiler frequently tells me that there are segmentation faults in my code)
P.S-i am a begginer.Just three weeks into c language and we are learning about loops.
The ordering of statements matters.
b = c;
a = b;
When this runs, b and a will both be equal to the original value of c, and the old value of b has been lost. This is probably not what you wanted.
a = b;
b = c;
When this runs, a will equal the old value of b, and b will equal the original value of c.
In Fibonacci series, a new number is generated as sum of previous two numbers.
Lets say previous two numbers were A and B and the newly generated number is C. Now for the next iteration you need to forget A and B & C are your new previous numbers.
To make B and C you new A and B you need to do:
A = B // B becomes the new A
B = C // C becomes the new B
what you are doing is:
B = C // C becomes the new B, but you've not saved the old value of B!!!
A = B // Old value of B gone..B is now C, which is assigned to A
Lines are executed in order, so in the first example b becomes c before a becomes b, in effect you are assigning c to both a and b creating some kind of exponential series (but of zeroes) instead of the fibonacci sequence.
A segmentation fault means that your program is accessing memory somewhere where it is not allowed to access memory, usually because you are dereferencing an invalid pointer or accessing an array out of bounds.
Look at this in isolation:
c = a + b ;
printf("%d \t", c) ;
b=c;
a=b;
The value of both a and bafter performing this will be c.
c = a + b ;
printf("%d \t", c) ;
a=b;
b=c;
If you re-arrange the statements, a gets the old value of b, and b gets the new value of c.
It is the same logic right. why does the first code give me wrong output?
Have you ever wondered, why
printf("Enter the limit : ") ;
scanf("%d", &n) ;
printf("\nThe fibonacci series is : \n\n") ;
first outputs Enter the limit, then waits for you to input a number, then outputs The fibonacci series is – in that particular order?
Why not the other way around or everything at the same time?
What are segmentation faults?
A simple google search would have given you tons of explanations. It means you have accessed memory, that is not yours to access.