N команд участвуют в турнире по крикету лиги на Марсе, где каждый
пара отдельных команд играет друг с другом ровно один раз. Таким образом, есть всего
из (N × (N1)) / 2 совпадений. Эксперт назначил силу каждой команде,
положительное целое число. Странно, что марсианские толпы любят односторонние матчи
и доход от рекламы, полученный от матча, является абсолютной величиной
разница между сильными сторонами двух матчей. Учитывая
Сильные стороны N команд, найти общий доход от рекламы, заработанный от всех
спички.
Формат ввода
Строка 1: одно целое число, N.
Строка 2: N целых чисел, разделенных пробелами, сильные стороны N команд.
#include using namespace std; int main() < int n; cin>>n; int stren[200000]; for(int a=0;a>stren[a]; long long rev=0; for(int b=0;bstren[c]) rev+=(long long)(stren[pos]-stren[c]); else rev+=(long long)(stren[c]-stren[pos]); > > cout
Можете ли вы дать мне решение ??
Решение
Перепишите ваш цикл как:
Как увеличить время работы iPhone
sort(stren); for(int b=0;b(stren[b]); >
Почему это работает
Ваши петли составляют все пары из 2 чисел и добавляют разницу к обороту. Так в отсортированном массиве, б го элемент вычитается (n-1-b) раз и добавляется b раз. Отсюда и число 2 * b — n + 1
Может быть 1 микрооптимизация, которая, возможно, не нужна:
sort(stren); for(int b = 0, m = 1 — n; b < n; b++, m += 2) < rev += m * static_cast(stren[b]); >
Другие решения
Вместо if заявление, использование
abs возвращает положительную разницу между двумя целыми числами. Это будет намного быстрее, чем if тест и последующее ветвление. (long long) приведение также не требуется, хотя компилятор, вероятно, оптимизирует это.
Есть и другие варианты оптимизации, которые вы могли бы сделать, но этот должен сделать это. Если твой abs Функция плохо реализована в вашей системе, вы мог всегда используйте эту быструю версию для вычисления абсолютного значения i :
(i + (i >> 31)) ^ (i >> 31) для 32 бит int ,
Это не имеет никакого ветвления вообще и победило бы даже встроенную тройную! (Но вы должны использовать int32_t как ваш тип данных; если у вас есть 64 бит int тогда вам нужно будет скорректировать мою формулу.) Но мы здесь в области микрооптимизации.
for(int b = 0; b < n; b++) < for(int c = b; c < n; c++) < rev += abs(stren[b]-stren[c]); >>
Это должно дать вам увеличение скорости, может быть достаточно.
Интересным подходом может быть свертывание сильных сторон массива, если это распределение довольно мало.
std::unordered_map strengths; for (int i = 0; i < n; ++i) < int next; cin >> next; ++strengths[next]; >
Таким образом, мы можем уменьшить количество вещей, которые мы должны суммировать:
long long rev = 0; for (auto a = strengths.begin(); a != strengths.end(); ++a) < for (auto b = std::next(a), b != strengths.end(); ++b) < rev += abs(a->first — b->first) * (a->second * b->second); // ^^^^ stren diff ^^^^^^^^ ^^ number of occurences ^^ > > cout
Если сильные стороны часто повторяются, это может спасти много циклов.
Только так можно ограничить время работы любого приложения на Android | Ставим таймер в приложениях!
Что именно мы делаем в этой задаче: Для всех комбинаций пар элементов мы складываем абсолютные значения разностей между элементами пары. то есть рассмотрим пример ввода
Ans (принимать только абсолютные значения) = (3-10) + (3-3) + (3-5) + (10-3) + (10-5) + (3-5) = 7 + 0 + 2 + 7 + 5 + 2 = 23
Обратите внимание, что я исправил 3, перебрал оставшиеся элементы, нашел различия и добавил их в Ans, затем исправил 10, перебрал оставшиеся элементы и так до последнего элемента
К сожалению, для вышеуказанной процедуры требуется N (N-1) / 2 итераций, что было бы неприемлемо для ограничения по времени.
Можем ли мы улучшить это?
Давайте отсортируем массив и повторим эту процедуру. После сортировки образец ввода теперь 3 3 5 10
Давайте начнем с исправления наибольшего элемента 10 и итерации по массиву, как мы делали раньше (конечно, сложность по времени такая же)
Ответ = (10-3) + (10-3) + (10-5) + (5-3) + (5-3) + (3-3) = 7 + 7 + 5 + 2 + 2 = 23
Оптимизация программного кода. Способы экономии памяти, сокращение времени исполнения
Оптимизация — модификация системы для улучшения её эффективности. Система может быть одиночной компьютерной программой, набором компьютеров или даже целой сетью, такой как Интернет.
Хотя целью оптимизации является получение оптимальной системы, истинно оптимальная система в процессе оптимизации достигается далеко не всегда. Оптимизированная система обычно является оптимальной только для одной задачи или группы пользователей: где-то может быть важнее уменьшение времени, требуемого программе для выполнения работы, даже ценой потребления большего объёма памяти; в приложениях, где важнее память, могут выбираться более медленные алгоритмы с меньшими запросами к памяти.
Более того, зачастую не существует универсального решения, которое работает хорошо во всех случаях, поэтому инженеры используют компромиссные (англ. tradeoff) решения для оптимизации только ключевых параметров. К тому же, усилия, требуемые для достижения полностью оптимальной программы, которую невозможно дальше улучшить, практически всегда превышают выгоду, которая может быть от этого получена, поэтому, как правило, процесс оптимизации завершается до того, как достигается полная оптимальность. К счастью, в большинстве случаев даже при этом достигаются заметные улучшения.
Способы экономии памяти.
Следует обращать особое внимание на выделение памяти под данные структурных типов (массивов, записей, объектов и т.п.).
При ограничениях на использование памяти следует выбирать алгоритмы обработки, не требующие дублирования исходных данных структурных типов в процессе обработки. (пример: алгоритмы сортировки массивов (сортировка методом «пузырька»)).
Если в программе необходимы большие массивы, используемые ограниченное время, то их можно размещать в динамической памяти и удалять при завершении обработки.
Следует помнить, что при передаче структурных данных в программу «по значению» копии этих данных размещаются в стеке. Избежать копирования удается, если передавать данные «по ссылке», но как неизменяемые (описанные const). Тогда размещается в стеке
только адрес данных.
Способы уменьшения времени выполнения.
При написании циклических участков программы необходимо:
· выносить вычисление константных, т.е. не зависящих от параметров цикла, выражений из циклов;
· избегать «длинных» операций умножения и деления, заменяя их сложением, вычитанием и сдвигами;
· минимизировать преобразования типов в выражениях;
· оптимизировать запись условных выражений – исключать лишние проверки;
· исключать многократные обращения к элементам массивов по индексам (особенно многомерных, так как при вычислении адреса элемента используются операции умножения на значение индексов) – первый раз прочитав из памяти элемент массива, следует запомнить его в скалярной переменной и использовать в нужных местах;
· избегать использование различных типов в выражении и т.п.
Химические и биологические негативные факторы, их воздействие на человека и меры защиты от них.
Пары, газы, жидкости, аэрозоли, химические смеси, соединения при контакте с организмом человека могут вызывать изменения в состоянии здоровья или заболевания. Воздействие вредных веществ на человека может сопровождаться отравлениями и травмами.
Химические вещества в зависимости от их практического использования классифицируются на:
· промышленные яды — используемые в производстве органические растворители (например, дихлорэтан), топливо (например, пропан, бутан), красители (например, анилин) и др.;
· ядохимикаты — используемые в сельском хозяйстве пестициды и др.;
· бытовые химикаты — применяемые в виде пищевых добавок (например, уксус), средства санитарии, личной гигиены, косметики и т. д.;
· биологические растительные и животные яды, которые содержатся в растениях, грибах, у животных и насекомых;
· отравляющие вещества (ОВ) — зарин, иприт, фосген и др.
В организм человека вредные вещества могут попадать через органы дыхания, желудочно-кишечный тракт, кожные покровы. Основным же путем проникновения являются органы дыхания.
По характеру воздействия на человека вредные вещества подразделяются на:
· общетоксические — вызывающие отравление всего организма или поражающие отдельные системы: центральную нервную систему, кроветворные органы, печень, почки (углеводороды, спирты, анилин, сероводород, синильную кислота и ее соли, соли ртути, хлорированные углеводороды, оксид углерода и др.);
· раздражающие — вызывающие раздражение слизистых оболочек, дыхательных путей, глаз, легких, кожи (органические азотокрасители, диметиламинобензол и другие антибиотики и др.);
· сенсибилизирующие — действующие как аллергены (формальдегид, растворители, лаки и др.);
· мутагенные — приводящие к нарушению генетического кода, изменению наследственной информации (свинец, марганец, радиоактивные изотопы и др.); канцерогенные — вызывающие злокачественные опухоли (хром, никель, асбест, бенз(а)пирен, ароматические амины и пр.);
· влияющие на репродуктивную (детородную) функцию — вызывающие возникновение врожденных пороков, отклонений от нормального развития детей, влияющие на нормальное развитие плода (ртуть, свинец, стирол, радиоактивные изотопы, борная кислота и др.).
Защита человека от негативных химических факторов.
1. Защита от загрязнения воздушной среды
1.2. Средства очистки воздуха от вредных веществ
2. Защита от загрязнения водной среды
2.1. Методы и средства очистки воды
2.1.8. Биологическая очистка
2.2. Обеспечение качества питьевой воды
2.2.1. Обеззараживание воды
2.2.1.3. Очистка ультрафиолетовым способом
2.2.2. Сорбционная очистка питьевой воды
2.2.3. Опреснение и обессоливание воды
3. Средства индивидуальной защиты
Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:
Познавательно:
Отличие вещных правоотношений от обязательственных Разграничение вещных и обязательственных прав РП не известно. В РП существовала классификация исков.
Порядок отправления вспомогательного локомотива на закрытый перегон для оказания помощи и следование его по перегону (ИДП, Приложение№7 п.5, п.6, п.11, п.13; №2817р, п.9.12, 9.13) Вспомогательный локомотив во всех случаях отправляется на перегон.
Алгоритм выполнения манипуляции. «Контрольное кормление» «Контрольное кормление» Цель: определить среднее количество молока, получаемое ребенком при кормлении грудью.
Строение коллоидных мицелл Коллоидные системы состоят из дисперсной фазы и дисперсионной среды.
Примерные фабулы административных правонарушений АДМИНИСТРАТИВНЫЕ ПРАВОНАРУШЕНИЯ, ПОСЯГАЮЩИЕ НА ОБЩЕСТВЕННЫЙ ПОРЯДОК И ОБЩЕСТВЕННУЮ БЕЗОПАСНОСТЬ Ст.
Источник: studopedia.ru
Оптимизация времени выполнения программы на С++ (убираем условные переходы)
2013-05-17 в 18:39, admin , рубрики: c++, Алгоритмы, оптимизация программ, Программирование, С++, метки: Алгоритмы, оптимизация программ, Программирование, С++
При оптимизации времени выполнения алгоритма, использующего LDPC декодер, профайлер привел к функции, вычисляющей следующее значение:
где a и b — целые числа. Количество вызовов шло на миллионы, а реализация ее была достаточно проста и безхитростна:
int LLR(int a, int b) < if (a>0) return (b>0) ? __min(a,b) : -__min(a,-b); else return (b>0) ? -__min(-a,b) : __min(-a,-b); >
Функция состоит, по сути, из трех последовательных операций сравнения. Это дает (с учетом оптимизации компилятора) два (если числа разных знаков) или три (если одного) условных перехода для получения результата. Вспомнив о потенциальных проблемах конвеера при большом количестве условных переходов было решено уменьшить их количество или даже избавиться от них. Для оценки быстродействия был написан небольшой
тестовый проект
#include static inline int LLR(int a, int b) < if (a>0) return (b>0) ? __min(a,b) : -__min(a,-b); else return (b>0) ? -__min(-a,b) : __min(-a,-b); > int _tmain(int argc, _TCHAR* argv[]) < SetPriorityClass(GetCurrentProcess(),REALTIME_PRIORITY_CLASS); SetThreadPriority(GetCurrentThread(),THREAD_PRIORITY_TIME_CRITICAL); srand(0); int x(0); __int64 t1,t2; QueryPerformanceCounter((LARGE_INTEGER*) for (size_t i=0;i>4;i++) < int a = rand() — RAND_MAX / 2; int b = rand() — RAND_MAX / 2; /* x += LLR(a,b);*/ >QueryPerformanceCounter((LARGE_INTEGER*) t2 -= t1; QueryPerformanceFrequency((LARGE_INTEGER*) _tprintf_s(_T(«%f»),t2/(t1*1.)); return 0; >
Сборка производилась в MSVS 2008 в конфигурации Release (настройки по умолчанию) для платформы x86.
Для начала, закомментируем вызов расчетной функции чтобы оценить время выполнения цикла с генерацией случайных чисел (к сожалению, вызов QueryPerformanceCounter() сам по себе довольно медленный и приводит к значительному искажению результата если его делать внутри цикла). Запускаем проект несколько раз, чтобы убедится в повторяемости результата. На машине с процессором Intel Core i7-3770 c частотой 3.4 ГГц время выполнения составляет в среднем 9.2 секунды. Если раскомментировать вызов расчетной функции, пересобрать проект и повторить эксперимент — получаем примерно 11.5 секунд. Прирост времени выполнения налицо, с ним и будем бороться.
Попробуем избавиться от условных операторов. Для начала выясним знак произведения a и b. Вычислять его в лоб некорректно из-за возможного переполнения. Так как нам важен только знак (то есть значение бита знакового разряда целого числа), то уместно воспользоваться операцией xor для определения знака произведения a и b. Далее, сдвинем результат a xor b вправо на 31 бит (оставляя только знаковый разряд) и получим 0 в случае неотрицательного числа и 1 в случае отрицательного. Умножим это значение на два, вычтем из единицы и получим -1 для отрицательного числа и 1 для неотрицательного:
int sign = 1-2*((unsigned)a^b)>>31);
Теперь рассчитаем модули a и b. Аналогичным методом определяем знаковые коэффициенты a и b и умножаем на них:
int c; c = 1-2*((unsigned)a)>>31); a *= c; c = 1-2*((unsigned)b)>>31); b *= c;
Перейдем к расчету минимума. Поскольку a и b уже имеют неотрицательные значения, рассчитать минимум можно, ориентируясь на знак их разности:
int numbers[2], min; numbers[0] = b; numbers[1] = a; a -= b; c = (unsigned(a))>>31; min = numbers[c];
Соберем все вместе и получим
следующую функцию
static inline int LLR_2(int a, int b) < int sign, numbers[2]; sign = 1-2*((unsigned)a^b)>>31); a *= 1-2*((unsigned)a)>>31); b *= 1-2*((unsigned)b)>>31); numbers[0] = b; numbers[1] = a; a -= b; return sign*numbers[((unsigned)a)>>31]; >
Заменим вызов LLR() на LLR_2() и посмотрим, что получилось. В ассемблерном коде теперь ни одного условного перехода, зато появились три инструкции целочисленного умножения imul (умножение на 2 компилятор сам заменяет на сдвиг). Прогнав тестовую программу, получаем следующий результат — время выполнения составляет 9.4 секунды! Итого, сравнивая времена «нетто» (2.1 и 0.2 секунды соответственно) для двух вариантов расчета искомого значения, получаем десятикратное увеличение скорости выполнения требуемой операции.
Попробуем пойти еще немного дальше. Целочисленное умножение необходимо только для перемены знака числа, которую можно выполнить напрямую. В частности, вычисление модуля числа a можно реализовать следующим образом:
unsigned int mask[] = ; unsigned int constant[] = ; int c = ((unsigned)a)>>31; a = a^mask[c]+constant[c];
И наконец, заменим сдвиг вправо на 31 бит единичным циклическим сдвигом влево с помощью функции _rotl(). Забегая вперед отметим, что компилятор преобразует ее вызов напрямую в инструкцию rol без использования call. Соберем все вместе еще раз и получим
третий вариант
static unsigned int mask[] = ; static unsigned int constant[] = ; static inline int LLR_3(int a, int b)
Заменяем вызов LLR()_2 на LLR_3() и видим, что значимого прироста это не дает (время выполнения составляет примерно те же 9.4 секунды с небольшой разницей в третьем знаке в меньшую сторону). Получается, что imul на современных процессорах выполняется довольно быстро!
Вернемся к алгоритму, с которого все началось. Описанной оптимизацией только лишь одной функции удалось сократить время обработки единичного блока данных со 160 до 140 секунд (при выполнении на i7), что составляет более 10% и является весьма неплохим результатом. На очереди еще несколько похожих функций…
Ну и напоследок предлагаю вариант реализации функции определения максимума двух целых 32-разряздных чисел. Написан он был уже число из академического любопытства. Желающие могут не спешить заглядывать под спойлер и попробовать реализовать подобное сами. Вариант без условных переходов работает примерно втрое быстрей стандартного макроса __max() (при выполнении на i7). Удачи в оптимизации ваших программ!
Скрытый текст
static inline int max(int a, int b) < int numbers[2][2]; numbers[0][0] = b; numbers[0][1] = a; numbers[1][0] = a; numbers[1][1] = b; int sign_a = (unsigned)a>>31; int sign_b = (unsigned)b>>31; int sign_ab = (unsigned)(a^b)>>31; int abs_a = (1-2*sign_a)*a; int abs_b = (1-2*sign_b)*b; int sign_a_b = (unsigned)(abs_a-abs_b)>>31; int c0 = sign_ab; int c1 = ((1^(sign_a_b)^(sign_a | sign_b)) sign_a); int result = numbers[c0][c1]; return result; >
Источник: www.pvsm.ru