Блог пользователя Easy_

Автор Easy_, 10 лет назад, По-русски

Добрый день, на acmp.ru есть такая задача: Подарки

Я пытался решить таким образом:

Если входные данные:

5 10
4 7 4 3 10

Сначало сортировал массив по неубыванию,

3 4 4 7 10

А далее делал так:

while(M > 0)
	{
		int t = A[1] - A[0];
		if(M > t)
		{
			M -= (t + 1);
			A[0] += (t + 1);
		}
		else
		{
			A[0] += M;
			M = 0;
		}
		
		i = 0;
		while(A[i] > A[i + 1] && i < N - 1)
			swap(A[i], A[i + 1]), i++;
	}

А — отсортированный массив

N — кол. элементов массива

M — кол. конфет

Надеюсь по алгоритму, идея решения ясна.. В конце работы алгоритма первый элемент массива и будет ответом.

Но такое решени не эффективное на больших входных данных и получаю TL на 10 тесте.

Теперь хочу попробовать решить через двоичные деревья, т.к. это у меня работает за O(N)

while(A[i] > A[i + 1] && i < N - 1)
			swap(A[i], A[i + 1]), i++;

А если сделать через min heap, то будет за O(log N).

У меня возникло 2 вопроса:

1) Как можно реализовать этот min heap самому, что бы там были методы добавления, и удаления корневого элемента? Если у кого есть пример, буду благодарен. В сети не нашел хороших примеров, а сам реализовал совсем не правильно.

2) Как тоже самое сделать через priority_queue? Проблема в том, что по умолчанию этот контейнер в С++ в корневом элементе хранит максимальный элемент, т.е. max heap. А мне нужно наоборот.

Я в справочнике читал, что там ему можно параметр передавать компатор(не знаю как правильно называется). В сети нашел несколько примеров, только там этот "компатор" был классом у которого много разных методов и перегруженных операторов. Тупо copy/paste не стал делать, хотел бы разобраться что и зачем.

Если кто знает, подкажите пожалуйста как сделать так, что бы в этом контейнере сортировка была по неубыванию.

Буду благодарен.

  • Проголосовать: нравится
  • -8
  • Проголосовать: не нравится

»
10 лет назад, # |
  Проголосовать: нравится +11 Проголосовать: не нравится

2) умножить все на -1.

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится +21 Проголосовать: не нравится

    Надо специально для таких умножающих на -1 дать задачу, где были бы ограничения -2147483648 <= value <= 2147483647

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится +13 Проголосовать: не нравится

      Совсем ушлые товарищи могут сделать замену x -> ~x.

»
10 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Храним кучу в массиве.

Тогда корень a[1], а сыновья вершины i — 2*i,2*i+1;

Дальше нам нужны две функции — sift_up и sift_down. sift_up проверяет для вершины верно ли, что она больше родителя. Если да — выходим. Иначе меняем местами вершину и ее родителя и рекурсивно запускаемся от родителя. sift_down проверяет, что вершина меньше ее сыновей. Если да — выходим. Иначе меняем вершину с ее МЕНШЬШИМ сыном и запускаемся от него. Реализовывается это довольно просто.

А алгоритм решения задачи таков. Запускаем sift_up по очереди от всех элементов массива слева направо. Затем m раз увеличиваем a[1] и запускаем sift_down(1), чтобы "утопить" вершину и получить новый минимум. Ответ будет в a[1].

Если что непонятно — спрашивайте.

»
10 лет назад, # |
Rev. 2   Проголосовать: нравится 0 Проголосовать: не нравится

В чем проблема написать бинпоиск по ответу или вообще в тупую за N?

UPD: написал динамику за N. Accepted. http://pastebin.com/XSi9hAfN

Будут вопросы — спрашивай.

»
10 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Можно еще массив в set засунуть и m раз сделать ++(*a.begin());

»
10 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Немного оффтопа — как уже написали выше, можно решать с мультисетом, и брать минимум как mset.begin(); можно написать бинпоиск по ответу (и при фиксированном ответе проверять, влезет ли нужное количество конфет наивно); а еще можно написать ту же симуляцию, но блочно (т.е. вместо первого элемента рассматриваем весь первый блок из элементов, у которых одинаковое значение — мы можем за одну операцию заполнить этот блок и объединить его со следующим, или же посчитать ответ, если остался единственный блок или конфет не хватит для того, чтобы сравнять текущий первый блок с текущим вторым).

  • »
    »
    10 лет назад, # ^ |
      Проголосовать: нравится 0 Проголосовать: не нравится

    Спасибо всем большое!

    Я пробовал через multiset, тоже получаю TL на 10 тесте.

    Вот решение, может я что-то не правильно реализовал..?

    #include <fstream>
    #include <algorithm>
    #include <set>
     
    #define LL long long
     
    using namespace std;
     
    fstream in("input.txt"), out("output.txt", ios::out);
     
    int i, t, z, p;
    multiset<int> A;
    multiset<int>::iterator tt;
    
    int main()
    {
        int N, M;
        in >> N >> M;
        for(int i = 0; i < N; i++)
    	{
            in >> p;
            A.insert(p);
        }
    
        int a, b;
        tt = A.begin();
        while(M)
        {
           a = *tt;
           tt++;
           b = *tt;
           z = b - a + 1;
    	   if(M >= z)
    	   {
    	   		int r = *A.begin() + z;
    			A.erase(A.begin());
    			A.insert(r);
    			M -= z;
    	   }
    	   else
    		{
    			int r = *A.begin() + M;
    			A.erase(A.begin());
    			A.insert(r);
    			M = 0;
    		}
    		
        }
      
      	out << *A.begin();
      	
        return 0;
    }
    

    И еще, не у кого нету реализации min-heap? хотел бы посмотреть на хорошую реализацию.

    Я в книге Кормена (Алгоритмы, посмтроение и анализ) прочитал главу, поробовал реализовать — не получилось.

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      Не понятно, что ты пишешь.

      Простое моделирование за MlogN = 10^7 в худшем случае.

      for i = 1 .. m (*A.begin())++;

    • »
      »
      »
      10 лет назад, # ^ |
        Проголосовать: нравится 0 Проголосовать: не нравится

      http://code.google.com/p/yaal/source/browse/lib/main/net/egork/collections/heap/Heap.java

      (массив at и все, что с ним связано, лучше удалить, если он действительно не нужен)

      Правда, непонятно, зачем, когда есть priority_queue. Лучше запомни, как собственный компаратор в нее передавать.

»
10 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

Кажется, тебе очень помогут вот эти видеокурсы. Описание кучи и пирамидальной сортировки там тоже есть.

»
10 лет назад, # |
  Проголосовать: нравится 0 Проголосовать: не нравится

http://e-maxx.ru/algo/randomized_heap

MinMax Heap в 10 строчек,очень хорошо расписано.