Оптимизация стандартного итерационного алгоритма

0

В связи с проблемой проблемы здесь: Ссылка

#include <iostream>

using namespace std;


int main() {
    int T,*x,i,j,k,a,res,pres;
    long Q,N,p,q;
    cin>>T;
    for(k=0;k<T;k++)
    {
        cin>>N>>Q;
        x=new int[N];
        for(i=0;i<N;i++)
        {
            cin>>x[i];
        }
        for(i=0;i<Q;i++)
        {
            pres=-999;
            cin>>a>>p>>q;
            for(j=p-1;j<q;j++)
            {
                res=a xor x[j];
                if(pres<res)
                {
                    pres=res;
                }
            }
            cout<<pres<<endl;

        }
        delete [] x;
    }
    return 0;
}

Я получаю ограничение по времени (подразумевая, что проблема может быть оптимизирована) по более крупным задачам (N = 100000) (N, Q, T maxing out). Я полагаю, что мне нужно оптимизировать алгоритм, используя некоторую предварительную обработку. Мое решение - O (NQT) для всей проблемы. Проблема должна будет оценивать для всех возможных XOR для заданных лимитов в запросе. Таким образом, проблема должна будет идти (qp) [Может быть в max N] раз для запроса. Я не могу понять, как избежать этого. Хит или направление было бы действительно оценено. Я думаю о реализации кучи как-то, так что он вычитает запрос a из кучи, и den делает максимальную кучу, чтобы увидеть максимальную разницу и den xors. Но это тоже займет O (NQT)

  • 0
    Почему ваши петли начинаются с 1? Почему вы выделяете без освобождения? Почему вы объявляете переменные далеко от точки использования? Почему вы using namespace std; ? Сначала очистите код и получите огромные постоянные факторы.
  • 0
    Вычистил свои вещи. Мой основной код полностью очищен. Это было довольно сыро, прежде чем я убрал ненужные вещи. Начал с 1, потому что изначально не получал результат, просто чтобы убедиться, что все с 1 по N, поэтому данные идут в соответствии с алгоритмом, который я думал.
Показать ещё 7 комментариев
Теги:
optimization
encryption
algorithm
c-preprocessor

3 ответа

1

Я не думаю, что возиться с тем, что вы написали, поможет вам в скорости. Вы хотите что-то с лучшей временной сложностью.

Из вопроса я предполагаю, что они хотят что-то, что есть O (log N) для каждого запроса. Моя первоначальная мысль была деревом сегментов, но я не мог найти способ использовать их для максимизации a ^ x[i].

Я считаю, что вы должны использовать тот факт, что все числа меньше 2^15. Еще одно замечание - вы хотите максимизировать операцию xor. Скажем, у вас есть (в двоичном виде)

a = b_1 b_2 ... b_n

У вас либо есть, что все x[j] с p <= j <= q имеют самый старший бит, равный b_1, или некоторые x[j] для которых самый старший бит является дополнением к b_1. Это связано с тем, что b xor ~b = 1 для b in {0,1}. Вы выбираете только те j для которых MSB является дополнением к b_1, и продолжайте следующий бит (соответствующий b_2).

Проблема в том, что выполнение этой грубой силы хуже того, что вы уже делаете, но это может помочь вам в более быстрой реализации.

  • 0
    Хорошее выполнение операции XOR только с числами, у которых MSB x [j] является дополнением к a, уменьшит число no. операций XOR. но разве он не добавил бы N сравнений, чтобы решить, какие из них имеют дополненный MSB? Разве это не делает сложность времени такой же, как была?
  • 0
    Да, это тот момент, когда мой метод ломается. Я не знаю, как полностью решить вашу проблему, но я полагаю, что это как-то связано с тем, что числа все относительно малы (менее 2 ^ 15). Я отредактирую свой ответ, если я подумаю о чем-то лучше.
0

Здесь измененный код с предложениями, которые я сделал в комментариях.

Избегайте C++ iostreams в коде, чувствительном к производительности. (FWIW, избегайте iostreams в целом) Избегайте распределения/освобождения как можно больше. В приведенном ниже коде vector::resize будет следить за тем, чтобы вектор всегда имел по крайней мере необходимое пространство. Не производительность, а удобство чтения: используйте пробелы оператора aronud. Объявите переменные, близкие к тому, где они используются.

#include <cstdio>
#include <vector>
#include <algorithm>

int main() {
    int T;
    std::vector<int> x;

    std::scanf ("%d", &T);
    for (int k = 0; k < T ; ++k) {

        int N, Q;
        std::scanf ("%d%d", &N, &Q);
        x.resize (N);

        for (int i = 0; i < N; ++i)
            std::scanf ("%d", &x[i]);

        for (int i = 0; i < Q; ++i) {
            int a, p, q;
            std::scanf ("%d%d%d", &a, &p, &q);

            int pres = -999;
            for(int j = p - 1; j < q; ++j)
                pres = std::max (pres, a ^ x[j]);

            std::printf ("%d\n", pres);
        }
    }
    return 0;
}
0

Некоторые советы:

  • Все вызовы cin делают невозможным измерение производительности этого кода. вы должны прочитать все данные заранее из файлов.
  • Не выделяйте x каждый внешний вид, выделяйте один раз с помощью malloc и вызывается realloc чтобы сделать буфер длиннее, если это необходимо. Распределение памяти может замедлить работу.

Внутренний цикл очень прост, поэтому компилятор может его векторизовать. Убедитесь, что это действительно происходит, глядя на разборку. Если нет, используйте встроенные функции SSE для работы по 4 или 8 8 элементам за раз.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню