So I need some help again.I recently started doing medium level problems on codechef and hence I am getting TLE quite a lot.
So basically the question is to find the sum of of multiple maximum range queries given in the question.The initial range is given and the next values are calculated by a formula which is given in the problem.
I used segment trees to solve the problem,but I keep getting TLE for some sub-tasks.Please help me optimize this code.
Problem link- https://www.codechef.com/problems/FRMQ
//solved using segment tree
#include <stdio.h>
#define gc getchar_unlocked
inline int read_int() //fast input function
{
char c = gc();
while(c<'0' || c>'9')
c = gc();
int ret = 0;
while(c>='0' && c<='9')
{
ret = 10 * ret + c - '0';
c = gc();
}
return ret;
}
int min(int a,int b)
{
return (a<b?a:b);
}
int max(int a,int b)
{
return (a>b?a:b);
}
void construct(int a[],int tree[],int low,int high,int pos) //constructs
{ //the segment tree by recursion
if(low==high)
{
tree[pos]=a[low];
return;
}
int mid=(low+high)>>1;
construct(a,tree,low,mid,(pos<<1)+1);
construct(a,tree,mid+1,high,(pos<<1)+2);
tree[pos]=max(tree[(pos<<1)+1],tree[(pos<<1)+2]);
}
int query(int tree[],int qlow,int qhigh,int low,int high,int pos)
{ //function finds the maximum value using the 3 cases
if(qlow<=low && qhigh>=high)
return tree[pos]; //total overlap
if(qlow>high || qhigh<low)
return -1; //no overlap
int mid=(low+high)>>1; //else partial overlap
return max(query(tree,qlow,qhigh,low,mid,(pos<<1)+1),query(tree,qlow,qhigh,mid+1,high,(pos<<1)+2));
}
int main()
{
int n,m,i,temp,x,y,ql,qh;
long long int sum;
n=read_int();
int a[n];
for(i=0;i<n;i++)
a[i]=read_int();
i=1;
while(temp<n) //find size of tree
{
temp=1<<i;
i++;
}
int size=(temp<<1)-1;
int tree[size];
construct(a,tree,0,n-1,0);
m=read_int();
x=read_int();
y=read_int();
sum=0;
for(i=0;i<m;i++)
{
ql=min(x,y);
qh=max(x,y);
sum+=query(tree,ql,qh,0,n-1,0);
x=(x+7)%(n-1); //formula to generate the range of query
y=(y+11)%n;
}
printf("%lld",sum);
return 0;
}
Several notes:
It's great you are using fast IO routines.
Make sure you do NOT use modulo operation, because it is VERY slow. To calculate remainder, simply subtract N from the number until it becomes less that N. This would work much faster.
Your algorithm works in O((M+N) * log N) time, which is not optimal. For static RMQ problem, it is better and much simpler to use sparse table. It needs O(N log N) space and O(M + N log N) time.
Well , I think to get 100 points you need to use sparse table.
I tried to optimize your code https://www.codechef.com/viewsolution/7535957 (run time decreased from 0.11 sec to 0.06 sec)
but still not enough to pass subtask 3..
Related
I am trying to sort a large table of integers using different types of sorting algorithms like quick sort, bubble sort and merge Sort, all of these algorithms works just fine. However, When trying to sort a table with more than than 521096 elements using Merge Sort, the program just exits without throwing any error(I'm guessing in C this is a runtime error)
Note that Merge Sort works perfectly with a table that contains less than 921096 elements.
Note also that for example Quick Sort works fine with tables of any length(I've tried up to 1 Million elements).
Here is the code I'm using:
void fillTable(int *t,int n){
srand(time(NULL));
int signe=1;
for(int *p=t;p<t+n;p++){
*(p)=signe*rand()%n;
signe*=-1;
}
}
void mergeTables(int *tab,int l,int m,int r){
int i,j,k;
int n1=m-l+1;
int n2=r-m;
int lTab[n1],rTab[n2];
for(i=0;i<n1;i++){
lTab[i]=tab[l+i];
}
for(i=0;i<n2;i++){
rTab[i]=tab[m+1+i];
}
i=0;j=0;k=l;
while(i<n1 && j<n2){
if(lTab[i]<=rTab[j]){
tab[k]=lTab[i];
i++;
}
else{
tab[k]=rTab[j];
j++;
}
k++;
}
while(i<n1){
tab[k]=lTab[i];
i++;
k++;
}
while(j<n2){
tab[k]=rTab[j];
j++;
k++;
}
}
void diviserTab(int *tab,int l,int r){
if(r>l){
int m=(r+l)/2;
diviserTab(tab,l,m);
diviserTab(tab,m+1,r);
mergeTables(tab,l,m,r);
}
}
void mergeSort(int* t,int n){
diviserTab(t,0,n-1);
}
double getTime(void(*f)(int*,int),int* t,int n){
clock_t start,end;
start=clock();
f(t,n);
end=clock();
return (double)(end-start)/CLOCKS_PER_SEC;
}
and here is my Main:
int main(){
int *tab;
int i;
int n=521096;
tab=(int*)malloc(n*sizeof(int));
fillTable(tab,n);
printf("First 10 elements before sorting");
for ( i = 0; i < 10; i++)
{
printf("%5d\t",tab[i]);
}
printf("%f\n",getTime(mergeSort,tab,n));
printf("\nFirst 10 elements before sorting\n");
for ( i = 0; i < 10; i++)
{
printf("%5d\t",tab[i]);
}
return 0;
}
Now to the results:
if n=521095 (number of elements in the array)
First 10 elements before sorting
18187 -12205 23363 -27523 30572 -31906 5475 -10341 5178 -27678
it took 0.179000 to sort the array
First 10 elements after sorting
-32767 -32767 -32767 -32767 -32767 -32767 -32767 -32766 -32766 -32766
if n=521096
First 10 elements before sorting
18243 -31088 32141 -10616 9312 -356 25619 -26113 23731 -21465
(and it just exits)
You are allocating some large arrays on the stack. From your mergeTables function:
int lTab[n1],rTab[n2];
With a large array to sort, n1 and n2, and therefore lTab and rTab, can become large (half the size of your initial array), and the stack is typically fairly small. If the arrays don't fit, all sorts of strange things can happen. When I tried your program with a large array (10 million integers), the program crashed.
Quicksort and bubble sort are usually performed in situ, so I assume you didn't need all this extra space for them.
I changed your two arrays to this:
int *lTab = malloc(n1 * sizeof(int));
int *rTab = malloc(n2 * sizeof(int));
And then at the end of the function:
free(lTab);
free(rTab);
Let's say we want to write a function in C that finds a specified target value in an unsorted array of ints. In general, this is simple and runs in O(n) time:
int search(int *data, int len, int target)
{
int i;
for(i = 0; i < len; i++)
if(data[i]==target) return i;
return -1;
}
Let's say we're being masochistic and want to approach this with a divide and conquer algorithm instead. We'll run into trouble on the recursive part because we can't exclude half the array each time, like we can with binary search:
int search(int *data, int start, int stop, int target)
{
// Base case: we've divided the array into two size subarray
if(stop==start+1)
{
if(data[start]==target) return start;
if(data[stop]==target) return stop;
return -1;
}
/* The recursion part is tricky.
We *need* to parse both halves of the array, because we can't safely
exclude any part of the array; it's not sorted, so we can't predict
which half it's going to be in.*/
else
{
/** This obviously doesn't work. */
int mid = (stop-start)/2;
return search(data, start, mid, target);
return search(data, mid+1, stop, target);
}
}
Is there any way to make this work?
NOTE: This is not asking people to do my homework for me, as some of you may think when reading this question. It is, however, inspired by curiosity after I encountered this problem when trying to solve a question in an assignment that I've submitted earlier this week.
How about changing the recursive call to:
else
{
int mid = (stop-start)/2;
int x = search(data, start, mid, target);
if (x == -1)
return search(data, mid+1, stop, target);
else
return x;
}
I think the answer to your question is no, you can't achieve any benefit using the binary split approach if the data is unsorted.
If the data are not sorted you can not use binary search.
But divide and conquer can be used with the following recursive logic (linear search):
int search(int *data, int len, int target)
{
if (len == 0)
return -1;
else if (data[0] == target);
return 0;
else
return 1 + search(++data, len-1, target);
}
I'm writing a program to display the time needed to calculate a factorial of a given number 2 million times. I'm writing it using Debian Linux in the C/C++ Eclipse environment. When the program gets to int temp = n * rfact(n-1);, it hangs and won't do anything else.
Here's what I've got so far:
#include <stdio.h>
#include <time.h>
//prototypes
int rfact(int n);
main()
{
int n = 0;
int i = 0;
double result = 0.0;
clock_t t;
printf("Enter a value for n: ");
scanf("%i", &n);
printf("n=%i\n", n);
//get current time
t = clock();
//process factorial 2 million times
for(i=0; i<2000000; i++)
{
rfact(n);
}
printf("n=%i\n", n);
//get total time spent in the loop
result = (clock() - t)/(double)CLOCKS_PER_SEC;
//print result
printf("runtime=%d\n", result);
}
//factorial calculation
int rfact(int n)
{
int temp = n * rfact(n-1);
printf(i++);
return temp;
}
You are missing the base case, so you are running into an infinite recursion. You need to stop when you get to n == 1 or n == 0:
int rfact(int n)
{
if (n <= 0)
return 1;
return n * rfact(n-1);
}
Also, the factorial function is not really the best use case for recursion because the iterative version is arguably more readable and possibly a lot faster, but that's a different story :)
There is no base case in your rfact function. This means that the rfact(n-1) will be called forever.
I agree with people above me, you are missing the base case of recursion
But be aware of doing a factorial 2'000'000 times, your variable will go overflow apart from taking a lot of time for the computation to be terminated
I have written a code to calculate the minimum number of coins using Greedy algorithm and Dynamic algorithm, but the Dynamic algorithm part doesn't work properly. There is a Null value going to array, I can't find it. Please HELP me. I need a answer as soon as possible.
#include <stdio.h>
int n;
int denom[]={1,2,4,5,20,25};
int coinCounter(int n);
int main(){
printf("Please Enter a Number : ");
scanf("%d",&n);
int coinmin,orin,i;
orin=n;
i=coinmin=0;
for(i=(sizeof(denom)/4)-1;i>=0;i--){
coinmin =coinmin+n/denom[i];
n=n%denom[i];
}
printf("Coin Min By Greedy Algorithm : %d\n",coinmin);
printf("Dynamic Algorithm : %d\n",coinCounter(orin));
return 0;
}
int coinCounter(int n){
int opt[n];
int largest[n];
int i,j,a;
i=j=0;
for(j=1;j<=n;j++){
opt[j]=10000;
//printf("xxn");
for(i=(sizeof(denom)/4)-1;i>=0;i--){
if(denom[i]==j){
opt[j]=1;
largest[j]=j;
}
else if(denom[i]<j){
a=opt[j-denom[i]]+1;
}
if(a<opt[j]){
opt[j]=a;
largest[j]=denom[i];
}
}
}
return opt[n];
}
I edited the Code as following, but the answer is not coming
int coinCounter(int n){
int opt[n];
int largest[n];
int i,j,a;
i=j=0;
for(j=1;j<n;j++){
opt[j]=10000;
printf("xxn");
for(i=(sizeof(denom)/4)-1;i>=0;i--){
if(denom[i]==j){
opt[j]=1;
largest[j]=j;
}
else if(denom[i]<j){
a=opt[j-denom[i]]+1;
}
if(a<opt[j]){
opt[j]=a;
largest[j]=denom[i];
}
}
}
return opt[n-1];
}
hey these are the results I'm Getting
Please Enter a Number : 8
Coin Min By Greedy Algorithm : 3
Dynamic Algorithm : 1
Another answer I'm getting I can't figure out what I'm doing wrong
Please Enter a Number : 71
Coin Min By Greedy Algorithm : 4
Dynamic Algorithm : 3
1
int opt[n]; // not the right way to do dynamic allocation. Use malloc/calloc
int largest[n];
2
for(j=1;j<=n;j++){
^ array is indexed from 0...n-1, index-n is outside array bounds
Don't do this.
int coinCounter(int n){
int opt[n];
int largest[n]; <---- Don't do this. This does not work like you expect it to.
change to
int coinCounter(int n){
int opt[n];
int *largest = malloc(sizeof(int)*n);
Edit:
Another bug with the algorithm
your variable "a" is not initialized and you are using it in if condition.
think of the case when denom[i]>j
your variable "a" would not be initialized
so depending upon what garbage value it has , results will vary
bug is here , but it shows up when you change opt allocation, because that allocation changes the condition. What I want to say is - if (X<Y), depends on both X and Y. Problem is with X, but because you change Y, the condition changes and you get different result
im trying to solve this very first challange but i get stuck,
i like fast program, so i decided to use recursive method not iteration
unfortunately, when the input is a big integer (100000 > input > 1000000), its often crash
so i debug it, and it shows stack overflow error
please help me, i dont know what to do, ive tried to change data type to unsigned long, unsigned int, etc, but none of it works
here is my code,
im using ANSI C
#include "stdio.h"
int cek(int n) {
return n % 2;
}
int fung(int n,int c) {
if (n == 1) {
return c;
}
if (!cek(n)) {
return fung(n/2,++c);
}
else {
return fung((n*3)+1,++c);
}
}
int comp(int i,int j,int tmp) {
int temp;
if (i == j)
return tmp;
temp = fung(i,1);
if (temp > tmp)
return comp(++i,j,temp);
else
return comp(++i,j,tmp);
}
int main() {
int i,j,tmp;
while (scanf("%d %d",&i,&j)) {
if (i > j) {
tmp = i;
i = j;
j = tmp;
}
printf("%d %d %d\n",i,j,comp(i,j,0));
}
return 0;
}
PS: sorry for my stupidness, im really a newbie #_#
Recursion is not likely to be faster than iteration, and in fact it's likely to be slower.
The call stack has a limited size, and if your recursion goes deeper than that, there's nothing you can do about it. Especially in the Collatz problem, there's no way to tell up front how many steps you'll need. Rewrite this using an iterative method instead.
(If your compiler does tail call optimization, recursion might still work. But TCO is not required by the standard, so it will lead to unportable code. And apparently, your compiler does not optimize this particular tail call anyway.)
Not a C expert, but usually there is a call stack depth limit enforced by the compiler. Probably you can change this with a compiler flag, but this will not solve your problem. Making the algorithm iterative instead of recursive will fix it.
Recursive algorithms won't go faster than iterative ones, usually. But they are typically nicer to understand. (= more elegant)
Okay guys,
i found it!!!
so this is my code, i still use recursion but only for the inner loop fung(),
im not really impressed of it, because its need 0,5 sec to count input 1 and 1000000, someone's code outhere can do it in 0 sec, LOL
i change the outer loop comp() with iterative method,
look here
#include "stdio.h"
/*#include "windows.h"*/
int cek(int n) {
return n % 2;
}
unsigned int fung(unsigned int n,unsigned int c) {
if (n == 1) return c;
if (!cek(n)) return fung(n/2,++c);
else return fung((n*3)+1,++c);
}
/*
Above recursion will looked like this in iterative method
int func(int n) {
int c=1;
while (n != 1) {
c++;
if (n % 2 == 0)
n=n/2;
else
n=(n*3)+1;
}
return c;
}
*/
/*Outer Loop*/
int iter(int i,int j) {
int tmp1=0,tmp2;
while (i <= j) {
tmp2 = fung(i,1);
if (tmp1 < tmp2)
tmp1 = tmp2;
i++;
}
return tmp1;
}
int main() {
unsigned int i,j,s,f;
while (scanf("%d %d",&i,&j)) { /*UVa Standard, infinite loop*/
/*s = GetTickCount();*/
printf("%d %d %d",i,j,iter(i,j));
/*f = GetTickCount();
printf("%lu\n",f-s);*/
}
return 0;
}