#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#define INFILE "gutui.in"
#define OUTFILE "gutui.out"
/* #define DEBUG */
#define SCRIE_EROARE(eroare) fprintf( stderr, "Eroare in %s: %s\n", __func__, eroare );
/* Structura de gutuie */
typedef struct
{
int i_imax;
int i_greutate;
} gutuie_t;
/* Vrem sa sortam crescator dupa i_imax si descrescator dupa i_greutate */
int gutuie_compara( gutuie_t *una, gutuie_t *alta )
{
if( una->i_imax < alta->i_imax )
return -1;
if( una->i_imax > alta->i_imax )
return +1;
if( una->i_greutate > alta->i_greutate )
return -1;
if( una->i_greutate < alta->i_greutate )
return +1;
return 0;
}
gutuie_t *gutui_merge( int i_n1, gutuie_t *p_gutui1, int i_n2, gutuie_t *p_gutui2 )
{
gutuie_t *p_gutui3 = calloc( i_n1 + i_n2, sizeof(gutuie_t) );
int i1, i2, i;
for( i = i1 = i2 = 0; i1 < i_n1 && i2 < i_n2; ++ i )
p_gutui3[i] = gutuie_compara( p_gutui1 + i1, p_gutui2 + i2 ) < 0 ? p_gutui1[i1 ++] : p_gutui2[i2 ++];
while( i1 < i_n1 )
p_gutui3[i ++] = p_gutui1[i1 ++];
while( i2 < i_n2 )
p_gutui3[i ++] = p_gutui2[i2 ++];
if( i != i_n1 + i_n2 )
SCRIE_EROARE( "wtf, intorc mai putine elemente decat trebuie" )
return p_gutui3;
}
void gutui_merge_sort( int i_ngutui, gutuie_t *p_gutui )
{
if( i_ngutui <= 1 )
return;
int i_n1 = i_ngutui / 2;
int i_n2 = i_ngutui - i_n1;
gutuie_t *p_jumate1 = p_gutui;
gutuie_t *p_jumate2 = p_gutui + i_n1;
gutui_merge_sort( i_n1, p_jumate1 );
gutui_merge_sort( i_n2, p_jumate2 );
gutuie_t *p_sortate = gutui_merge( i_n1, p_jumate1, i_n2, p_jumate2 );
memcpy( p_gutui, p_sortate, i_ngutui * sizeof(gutuie_t) );
free( p_sortate );
}
#ifdef DEBUG
void gutui_afiseaza( int i_n, gutuie_t *p_gutui )
{
int i;
for( i = 0; i < i_n; ++ i )
printf( "(%d, %d); ", p_gutui[i].i_imax, p_gutui[i].i_greutate );
printf( "\n" );
}
#endif
int gutui_aduna_greutati( int i_n, gutuie_t *p_gutui )
{
int s = 0;
gutuie_t *p_last = p_gutui + i_n;
while( p_gutui < p_last )
s += (*(p_gutui ++)).i_greutate;
return s;
}
int gutui_calculeaza_greutate_maxima( int i_n, gutuie_t *p_gutui )
{
if( i_n <= 0 )
return 0;
int i_last_imax = p_gutui->i_imax;
int i_luat = 0, i_best = 0;
int i_disponibile;
int i;
int s = 0;
gutuie_t *p_best = p_gutui;
for( i = 0; i < i_n; ++ i )
{
i_disponibile = p_gutui[i].i_imax - i_last_imax;
if( i_disponibile > i - i_best )
i_disponibile = i - i_best;
if( i_disponibile > 0 )
{
s += gutui_aduna_greutati( i_disponibile, p_best );
p_best = p_gutui + i;
i_best = i;
i_luat += i_disponibile;
}
#ifdef DEBUG
printf( "%d -> %d disponibile, %d luat, %d suma\n", i, i_disponibile, i_luat, s );
#endif
}
s += gutui_aduna_greutati( i_luat - p_best->i_imax + 1, p_best );
#ifdef DEBUG
printf( "%d -> %d suma\n", i, s );
#endif
return s;
}
int main( int argc, char *argv[] )
{
int i_n = 0, i_h = 0, i_u = 0;
/* Citeste datele de intrare */
FILE *fin = fopen( INFILE, "r" );
if( !fin )
{
SCRIE_EROARE( "Nu pot deschide fisierul de intrare!" )
return 2;
}
fscanf( fin, "%d %d %d\n", &i_n, &i_h, &i_u );
gutuie_t *p_gutui = calloc( i_n, sizeof(gutuie_t) );
if( i_u == 0 )
SCRIE_EROARE( "Inaltimea la care se ridica gutuile este 0!" )
int i, i_inaltime;
for( i = 0; i < i_n; ++ i )
{
/* Pune o gutuie in lista */
fscanf( fin, "%d %d", &i_inaltime, &p_gutui[i].i_greutate );
p_gutui[i].i_imax = i_u != 0 ? (i_h - i_inaltime) / i_u : INT_MAX - 1;
}
/* Sorteaza gutuile */
#ifdef DEBUG
gutui_afiseaza( i_n, p_gutui );
#endif
gutui_merge_sort( i_n, p_gutui );
#ifdef DEBUG
gutui_afiseaza( i_n, p_gutui );
#endif
/* Vezi greutatea maxima */
int i_gmax = gutui_calculeaza_greutate_maxima( i_n, p_gutui );
free( p_gutui );
/* Scrie rezultate */
FILE *fout = fopen( OUTFILE, "w" );
fprintf( fout, "%d", i_gmax );
fclose( fout );
return 0;
}