Здравствуйте, Кодт, Вы писали:
К>А что, в BC++3 нет STL ? Вот это новость.
Там есть STL, но какая-то уж очень древняя — iostream.h! Многих алгоритмов там нету (хотя я не притрагивался к этой желтовато-голубой мерзости настолько, чтобы знать наверняка).
Здравствуйте, Olegator, Вы писали:
O>Случаем не с olympiads.ru задача, ? Торопись — времени почти не осталось. Для решения задачи, как тебе уже правильно подсказали, надо использовать кучу (heap). Только забей на STL, она поработила разум многих! Делов-то тут несколько строчек:
O>
O>int N;
O>int a[N]; // массив из N элементов
O>// функция номер раз - проталкивание вниз
O>void push_down(int idx)
O>{
O> while(true)
O> {
O> int lc = 2 * idx + 1;
O> int rc = lc + 1;
O> int least = idx;
O> if(lc < N && a[lc] < a[least])
O> least = lc;
O> if(rc < N && a[rc] < a[least])
O> least = rc;
O> if(least == idx)
O> break;
O> int t = a[least];
O> a[least] = a[idx];
O> a[idx] = t;
O> idx = least;
O> }
O>}
O>// функция номер двас - проталкивание вверх
O>void push_up(int idx)
O>{
O> while(true)
O> {
O> int p = (idx - 1) / 2;
O> if(idx == 0 || a[p] <= a[idx])
O> break;
O> int t = a[p];
O> a[p] = a[idx];
O> a[idx] = t;
O> idx = p;
O> }
O>}
O>// функция номер трис - делает из массива хип
O>void make_heap()
O>{
O> for(int i = N / 2 - 1; i >= 0; i--)
O> push_down(i);
O>}
O>// вынимает наименьший элемент и восстанавливает хип
O>int pop_min()
O>{
O> int val = a[0];
O> a[0] = a[--N];
O> push_down(0);
O> return val;
O>}
O>// вставляет элемент и восстанавливает хип
O>void insert(int val)
O>{
O> a[N] = val;
O> push_up(N);
O> N++;
O>}
O>
Да с olympiads.ru. Спасибо за код, он мне сильно помог разобраться с кучами))) А вы не подскажете мне, как можно достаточно быстро решить следующую задачу:
для всех i = 1...N найти наибольшую длину префкса слова X[1]X[2]...X[i] такую, что она является инвертным суффиксом. Вы меня надеюсь поняли? Тут трудная задача для осмысления.
Прямой перебор не годится, оень много времени тратится. Возможно алгоритм Кнута-Морриса-Пратта поможет, но он несколько другое считает.
Здравствуйте, Olegator, Вы писали:
O>Случаем не с olympiads.ru задача, ? Торопись — времени почти не осталось. Для решения задачи, как тебе уже правильно подсказали, надо использовать кучу (heap). Только забей на STL, она поработила разум многих! Делов-то тут несколько строчек:
O>
O>int N;
O>int a[N]; // массив из N элементов
O>// функция номер раз - проталкивание вниз
O>void push_down(int idx)
O>{
O> while(true)
O> {
O> int lc = 2 * idx + 1;
O> int rc = lc + 1;
O> int least = idx;
O> if(lc < N && a[lc] < a[least])
O> least = lc;
O> if(rc < N && a[rc] < a[least])
O> least = rc;
O> if(least == idx)
O> break;
O> int t = a[least];
O> a[least] = a[idx];
O> a[idx] = t;
O> idx = least;
O> }
O>}
O>// функция номер двас - проталкивание вверх
O>void push_up(int idx)
O>{
O> while(true)
O> {
O> int p = (idx - 1) / 2;
O> if(idx == 0 || a[p] <= a[idx])
O> break;
O> int t = a[p];
O> a[p] = a[idx];
O> a[idx] = t;
O> idx = p;
O> }
O>}
O>// функция номер трис - делает из массива хип
O>void make_heap()
O>{
O> for(int i = N / 2 - 1; i >= 0; i--)
O> push_down(i);
O>}
O>// вынимает наименьший элемент и восстанавливает хип
O>int pop_min()
O>{
O> int val = a[0];
O> a[0] = a[--N];
O> push_down(0);
O> return val;
O>}
O>// вставляет элемент и восстанавливает хип
O>void insert(int val)
O>{
O> a[N] = val;
O> push_up(N);
O> N++;
O>}
O>
Что то использование кучи(на основе ваших функций) даёт 5 раз неправильный ответ и на 2 тестах превышает время работы, в чём может быть проблема? Ведь алгоритм кучи самый быстрый в этой задачи, значит его и надо использовать. Если надо — вот мой исходник:
#include <stdio.h>
long N;
void tolkat_vniz(long idx,long* a)
{
while(1)
{
long lc = 2 * idx + 1;
long rc = lc + 1;
long least = idx;
if(lc < N && a[lc] < a[least])
least = lc;
if(rc < N && a[rc] < a[least])
least = rc;
if(least == idx)
break;
long t = a[least];
a[least] = a[idx];
a[idx] = t;
idx = least;
}
}
void tolkat_vverh(long idx,long* a)
{
while(1)
{
long p = (idx - 1) / 2;
if(idx == 0 || a[p] <= a[idx])
break;
long t = a[p];
a[p] = a[idx];
a[idx] = t;
idx = p;
}
}
void do_pir(long* a)
{
for(long i = N / 2 - 1; i >= 0; i--)
tolkat_vniz(i,a);
}
long take_minimum(long* a)
{
long val = a[0];
a[0] = a[--N];
tolkat_vniz(0,a);
return val;
}
void insert(long val,long* a)
{
a[N] = val;
tolkat_vverh(N,a);
N++;
}
int main()
{
FILE* infile;
infile = fopen("k.in","rt");
FILE* outfile;
outfile = fopen("k.out","wt");
// .................
float sum = 0;
long tmp;
fscanf(infile,"%ld \n", &N);
long * a = new long [N];
for(long i = 0; i < N; i++)
fscanf(infile, "%ld", &a[i]);
do_pir(a);
while(N > 1)
{
long tmp = (take_minimum(a) + take_minimum(a));
// .......................
insert(tmp,a);
sum = sum+0.05*tmp;
}
fprintf(outfile,"%f",sum);
fclose(infile);
fclose(outfile);
return 0;
}
Здравствуйте, sprsrpsh, Вы писали:
S>Что то использование кучи(на основе ваших функций) даёт 5 раз неправильный ответ и на 2 тестах превышает время работы, в чём может быть проблема? Ведь алгоритм кучи самый быстрый в этой задачи, значит его и надо использовать. Если надо — вот мой исходник:
S>
S>int main()
S>{
S> FILE* infile;
S> infile = fopen("k.in","rt");
S> FILE* outfile;
S> outfile = fopen("k.out","wt");
S> // .................
S> float sum = 0;
S> long tmp;
S> fscanf(infile,"%ld \n", &N);
S> long * a = new long [N];
S> for(long i = 0; i < N; i++)
S> fscanf(infile, "%ld", &a[i]);
S> do_pir(a);
S> while(N > 1)
S> {
S> long tmp = (take_minimum(a) + take_minimum(a));
S> // .......................
S> insert(tmp,a);
S> sum = sum+0.05*tmp;
S> }
S> fprintf(outfile,"%f",sum);
S> fclose(infile);
S> fclose(outfile);
S> return 0;
S>}
S>
Сдавал прямо в том виде, в котором запостил. Прошло все тесты.
Ну во-первых, float — маловато, может быть переполнение. Во-вторых, не надо каждый раз умножать на 0.05, достаточно объявить переменную sum типа long long (64-битное целое), в цикле прибавлять к ней tmp. А потом при выводе ("%f" лучше заменить на "%lf") умножить её на 0.05. В-третьих, придирка: коли уж используешь динамическую память, почему не освобождаешь её ? А вообще мой тебе совет: объявляй глобальные массивы и не парься.
Здравствуйте, sprsrpsh, Вы писали:
S>Да с olympiads.ru. Спасибо за код, он мне сильно помог разобраться с кучами))) А вы не подскажете мне, как можно достаточно быстро решить следующую задачу: S>для всех i = 1...N найти наибольшую длину префкса слова X[1]X[2]...X[i] такую, что она является инвертным суффиксом. Вы меня надеюсь поняли? Тут трудная задача для осмысления. S>Прямой перебор не годится, оень много времени тратится. Возможно алгоритм Кнута-Морриса-Пратта поможет, но он несколько другое считает.
Разумеется, понял . Как-никак сам участвую в ней. Вообще-то такие публичные решения строго караются. Надеюсь, администрация олимпиады не читает RSDN.ru. Если что, я буду всё усиленно отрицать .
ЗЫ. Любопытства ради: под каким именем участвуешь и от какой школы?
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[4]: Алгоритм
От:
Аноним
Дата:
20.01.06 14:05
Оценка:
Здравствуйте, Olegator, Вы писали:
O>Здравствуйте, sprsrpsh, Вы писали:
S>>Что то использование кучи(на основе ваших функций) даёт 5 раз неправильный ответ и на 2 тестах превышает время работы, в чём может быть проблема? Ведь алгоритм кучи самый быстрый в этой задачи, значит его и надо использовать. Если надо — вот мой исходник:
S>>
S>>int main()
S>>{
S>> FILE* infile;
S>> infile = fopen("k.in","rt");
S>> FILE* outfile;
S>> outfile = fopen("k.out","wt");
S>> // .................
S>> float sum = 0;
S>> long tmp;
S>> fscanf(infile,"%ld \n", &N);
S>> long * a = new long [N];
S>> for(long i = 0; i < N; i++)
S>> fscanf(infile, "%ld", &a[i]);
S>> do_pir(a);
S>> while(N > 1)
S>> {
S>> long tmp = (take_minimum(a) + take_minimum(a));
S>> // .......................
S>> insert(tmp,a);
S>> sum = sum+0.05*tmp;
S>> }
S>> fprintf(outfile,"%f",sum);
S>> fclose(infile);
S>> fclose(outfile);
S>> return 0;
S>>}
S>>
O>Сдавал прямо в том виде, в котором запостил. Прошло все тесты.
O>Ну во-первых, float — маловато, может быть переполнение. Во-вторых, не надо каждый раз умножать на 0.05, достаточно объявить переменную sum типа long long (64-битное целое), в цикле прибавлять к ней tmp. А потом при выводе ("%f" лучше заменить на "%lf") умножить её на 0.05. В-третьих, придирка: коли уж используешь динамическую память, почему не освобождаешь её ? А вообще мой тебе совет: объявляй глобальные массивы и не парься.
А как объвить глобальный массив с произвольным числом элементов? Я и не хотел использовать динамическую память, но приходится...
Может у меня что то со считыванием и выводом не так?
И какой спецификатор для float'а нужно использовать? У меня с ним глюки. А с z алгоритмом у меня несколько неверныч ответов и превышение времени. Программа:
#include <stdio.h>
long n;
void fz(char* s, long* z)
{
long l = -1, r = -1;
z[0] = n;
for (long i = 1; i < n; ++i)
{
if (i > r)
{
z[i] = 0;
while (i + z[i] < n && s[z[i]] == s[n-1-i - z[i]])
++z[i];
}
else
{
long t = z[i - l];
if (t < r - i + 1)
z[i] = t;
else
{
z[i] = r - i + 1;
while (i + z[i] < n && s[z[i]] == s[n-1-i - z[i]])
++z[i];
}
}
if (i + z[i] - 1 > r)
{
l = i;
r = i + z[i] - 1;
}
}
}
int main()
{
FILE* infile;
FILE* outfile;
//long n;
infile = fopen("h.in","rt");
outfile = fopen("h.out","wt");
fscanf(infile, "%ld",&n);
char* x = new char[n];
long* z = new long[n];
fscanf(infile, "%s", x);
fz(x,z);
for(long i = n-1; i>=0; i--)
fprintf(outfile, "%ld ",z[i]);
fclose(infile);
fclose(outfile);
return 0;
}
Кстати, almaz0@yandex.ru, никто кроме меня не заметит
Здравствуйте, <Аноним>, Вы писали:
А>А как объвить глобальный массив с произвольным числом элементов? Я и не хотел использовать динамическую память, но приходится...
Зачем же с произвольным? Там указано ограничение на N.
А>Программа:
[skip]
Почитай ту ссылку получше, посмотри что находит Z-функция.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[5]: Алгоритм
От:
Аноним
Дата:
20.01.06 14:18
Оценка:
Здравствуйте, Olegator.
Учёл Ваши замечания(кроме динамической памяти).
Не прошло 2 последних теста — неправильный ответ. В программе ошибку не нашёл, вроде всё логично:
#include <stdio.h>
long N;
void tolkat_vniz(long idx,long* a)
{
while(1)
{
long lc = 2 * idx + 1;
long rc = lc + 1;
long least = idx;
if(lc < N && a[lc] < a[least])
least = lc;
if(rc < N && a[rc] < a[least])
least = rc;
if(least == idx)
break;
long t = a[least];
a[least] = a[idx];
a[idx] = t;
idx = least;
}
}
void tolkat_vverh(long idx,long* a)
{
while(1)
{
long p = (idx - 1) / 2;
if(idx == 0 || a[p] <= a[idx])
break;
long t = a[p];
a[p] = a[idx];
a[idx] = t;
idx = p;
}
}
void do_pir(long* a)
{
for(long i = N / 2 - 1; i >= 0; i--)
tolkat_vniz(i,a);
}
long take_minimum(long* a)
{
long val = a[0];
a[0] = a[--N];
tolkat_vniz(0,a);
return val;
}
void insert(long val,long* a)
{
a[N] = val;
tolkat_vverh(N,a);
N++;
}
int main()
{
FILE* infile;
infile = fopen("k.in","rt");
FILE* outfile;
outfile = fopen("k.out","wt");
long sum = 0;
long tmp;
fscanf(infile,"%ld \n", &N);
long * a = new long [N];
for(long i = 0; i < N; i++)
fscanf(infile, "%ld", &a[i]);
do_pir(a);
while(N > 1)
{
long tmp = (take_minimum(a) + take_minimum(a));
insert(tmp,a);
sum = sum+tmp;
}
fprintf(outfile,"%f",0.05*sum);
fclose(infile);
fclose(outfile);
return 0;
}
Если Вам удастся найти здесь ошибку, будет очень хорошо. Я не нашёл
А>int main()
А>{
А> FILE* infile;
А> infile = fopen("k.in","rt");
А> FILE* outfile;
А> outfile = fopen("k.out","wt");
А> long long sum = 0;
А> long tmp;
А> fscanf(infile,"%ld \n", &N);
А> long * a = new long [N];
А> for(long i = 0; i < N; i++)
А> fscanf(infile, "%ld", &a[i]);
А> do_pir(a);
А> while(N > 1)
А> {
А> long tmp = (take_minimum(a) + take_minimum(a));
А> insert(tmp,a);
А> sum = sum+tmp;
А> }
А> fprintf(outfile,"%lf",0.05*sum);
А> fclose(infile);
А> fclose(outfile);
А> return 0;
А>}
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[7]: Алгоритм
От:
Аноним
Дата:
20.01.06 14:33
Оценка:
Здравствуйте, Olegator, Вы писали:
O>Здравствуйте, <Аноним>, Вы писали:
O>Попробуй так:
O>
А>>int main()
А>>{
А>> FILE* infile;
А>> infile = fopen("k.in","rt");
А>> FILE* outfile;
А>> outfile = fopen("k.out","wt");
А>> long long sum = 0;
А>> long tmp;
А>> fscanf(infile,"%ld \n", &N);
А>> long * a = new long [N];
А>> for(long i = 0; i < N; i++)
А>> fscanf(infile, "%ld", &a[i]);
А>> do_pir(a);
А>> while(N > 1)
А>> {
А>> long tmp = (take_minimum(a) + take_minimum(a));
А>> insert(tmp,a);
А>> sum = sum+tmp;
А>> }
А>> fprintf(outfile,"%lf",0.05*sum);
А>> fclose(infile);
А>> fclose(outfile);
А>> return 0;
А>>}
O>
Спасибо огромное, прошло все тесты С задачей H пока не исправил ошибки компиляции.
Мой ICQ 320-837-054, если у Вас есть номер, заходите, так быстрее будет общаться.
Re[6]: Алгоритм
От:
Аноним
Дата:
20.01.06 14:58
Оценка:
Здравствуйте, Olegator, Вы писали:
O>Здравствуйте, <Аноним>, Вы писали:
А>>А как объвить глобальный массив с произвольным числом элементов? Я и не хотел использовать динамическую память, но приходится...
O>Зачем же с произвольным? Там указано ограничение на N.
А>>Программа: O>
O>[skip]
O>
O>Почитай ту ссылку получше, посмотри что находит Z-функция.
С функцией разобрался, переделал её для задачи. Теперь нет превышения лимита времени, только неправильные ответы. Функция:
void fz(char* s, char* s2, long* z)
{
long l = -1, r = -1;
//z[0] = n;long i = 0;
while(s[i]==s2[i])
i++;
z[0] = i;
for (i = 1; i < n; ++i)
{
if (i > r)
{
z[i] = 0;
while (i + z[i] < n && s[z[i]] == s2[i + z[i]])
++z[i];
}
else
{
long t = z[i - l];
if (t < r - i + 1)
z[i] = t;
else
{
z[i] = r - i + 1;
while (i + z[i] < n && s[z[i]] == s2[i + z[i]])
++z[i];
}
}
if (i + z[i] - 1 > r)
{
l = i;
r = i + z[i] - 1;
}
}
}
Программа сама только читает данные, инвертирует строку и вызывает функцию. Так что проблема наверное с функцией.
На всякий случай приведу программу:
int main()
{
long i;
FILE* infile;
FILE* outfile;
//long n;
infile = fopen("h.in","rt");
outfile = fopen("h.out","wt");
fscanf(infile, "%ld \n",&n);
char* x = new char[n];
char* inv_x = new char[n];
long* z = new long[n];
fscanf(infile, "%s", x);
for(i = 0; i<n; i++)
inv_x[i] = x[n-1-i];
//fscanf(infile, "%s", x);
fz(x,inv_x,z);
for(i = n-1; i>=0; i--)
fprintf(outfile, "%ld ",z[i]);
fclose(infile);
fclose(outfile);
return 0;
}