Re[4]: Алгоритм
От: Olegator  
Дата: 20.01.06 00:34
Оценка:
Здравствуйте, Кодт, Вы писали:

К>А что, в BC++3 нет STL ? Вот это новость.


Там есть STL, но какая-то уж очень древняя — iostream.h! Многих алгоритмов там нету (хотя я не притрагивался к этой желтовато-голубой мерзости настолько, чтобы знать наверняка).
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[2]: Алгоритм
От: sprsrpsh  
Дата: 20.01.06 08:10
Оценка:
Здравствуйте, 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>


O>
O>int main()
O>{
O>    // .................

O>    make_heap();

O>    while(N > 1)
O>    {
O>        int sum = pop_min() + pop_min();
O>        // .......................
O>        insert(sum);
O>    }

O>    return 0;
O>}
O>


Да с olympiads.ru. Спасибо за код, он мне сильно помог разобраться с кучами))) А вы не подскажете мне, как можно достаточно быстро решить следующую задачу:
для всех i = 1...N найти наибольшую длину префкса слова X[1]X[2]...X[i] такую, что она является инвертным суффиксом. Вы меня надеюсь поняли? Тут трудная задача для осмысления.
Прямой перебор не годится, оень много времени тратится. Возможно алгоритм Кнута-Морриса-Пратта поможет, но он несколько другое считает.
Re[2]: Алгоритм
От: sprsrpsh  
Дата: 20.01.06 08:39
Оценка:
Здравствуйте, 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>


O>
O>int main()
O>{
O>    // .................

O>    make_heap();

O>    while(N > 1)
O>    {
O>        int sum = pop_min() + pop_min();
O>        // .......................
O>        insert(sum);
O>    }

O>    return 0;
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;
}
Re[3]: Алгоритм
От: Olegator  
Дата: 20.01.06 12:02
Оценка:
Здравствуйте, 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. В-третьих, придирка: коли уж используешь динамическую память, почему не освобождаешь её ? А вообще мой тебе совет: объявляй глобальные массивы и не парься.
... << RSDN@Home 1.1.4 stable rev. 510>>
Re[3]: Алгоритм
От: Olegator  
Дата: 20.01.06 12:02
Оценка:
Здравствуйте, sprsrpsh, Вы писали:

S>Да с olympiads.ru. Спасибо за код, он мне сильно помог разобраться с кучами))) А вы не подскажете мне, как можно достаточно быстро решить следующую задачу:

S>для всех i = 1...N найти наибольшую длину префкса слова X[1]X[2]...X[i] такую, что она является инвертным суффиксом. Вы меня надеюсь поняли? Тут трудная задача для осмысления.
S>Прямой перебор не годится, оень много времени тратится. Возможно алгоритм Кнута-Морриса-Пратта поможет, но он несколько другое считает.

Разумеется, понял . Как-никак сам участвую в ней. Вообще-то такие публичные решения строго караются. Надеюсь, администрация олимпиады не читает RSDN.ru. Если что, я буду всё усиленно отрицать .

Что касается задачи H. Там нужно применить Z-алгоритм. Думаю, тебе пригодится http://algolist.manual.ru/forum/showflat.php/Cat/0/Number/8048/page/0/fpart/1/vc/1.

ЗЫ. Любопытства ради: под каким именем участвуешь и от какой школы?
... << 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, никто кроме меня не заметит
Re[5]: Алгоритм
От: Olegator  
Дата: 20.01.06 14:16
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>А как объвить глобальный массив с произвольным числом элементов? Я и не хотел использовать динамическую память, но приходится...


Зачем же с произвольным? Там указано ограничение на 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;
}


Если Вам удастся найти здесь ошибку, будет очень хорошо. Я не нашёл
Re[6]: Алгоритм
От: Olegator  
Дата: 20.01.06 14:23
Оценка:
Здравствуйте, <Аноним>, Вы писали:

Попробуй так:

А>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;
}


Переменная long n объявлена как глобальная.
Re: Алгоритм
От: Radmir Россия  
Дата: 24.01.06 06:57
Оценка: -1
Объясните пожалуйста почему нельзя просто сложить все элементы массива и получить результат?
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Лучше спросить дорогу чем заблудиться
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.