Второ Българско Онлайн Състезание, 24.10.2004

 

Анализ и примерна реализация на задача COL.

 

Ще разгледаме четири подхода към задачата. Първите два са доста очевидни, а последният е оптималното решение на проблема:

 

1) Най-лесният начин да се справим със задачата е да заделим квадратна таблица DxD, в която дапомним числото за всеки отделен район. На актуализация за район (x,y) променяме директно клетката х,у в тази таблица, а на запитване четем пак директно от нея.

Ограничението за x,y обаче предполага заделяне на таблица 10 000 X 10 000, което прави 100 000 000 клетки. В С това ще означава 100 000 000 X 4 Bytes = 400 МB int-ове. Memory Limit за тази задача е 64МB.

 

2) Друго лесно решение е по-пестеливо откъм памет, но харчи прекомерно много време: да запазим в масив всички актуализации и на всяко запитване да го сканираме целия за данни относно клетката от запитването. Събираме всичко в една променлива и е отговорът на запитването. Времева сложност O(n*m), като n*m = max 100 000 * 100 000, което, разбира се, не може да се вмести във времевото ограничение.

 

3) Третият подход е малко по-сложен. Нека масивът, в който си записваме входа е A. След прочитане сортираме A. Сортираният А трябва да се състои от "блокове" информация за един и същ район: примерно от i дo j в А има данни за район (10,10), в позиция j+1 е единствената актуализация за (15,100), а от j+2 до k - за (20,60). Събираме всичките жители от тези клетки в променлива S, след което приравняваме информацията във всяка от тях на S.

 

За всяко запитване правим двоично търсене в А за посочения район. Когато попаднем в "блока" на този район, веднага имаме финалния брой жители в него.

 

4) За решение на всички тестове трябва да се реализира т.нар. hash-таблица. Всъщност, тази задача е класически пример за проблем, който изисква такава.

Какво е тя и как се имплементира може да се прочете в почти всяка книга за алгоритми.

 

 

От самолет се вижда, че броят на районите, за които евентуално ще постъпи някаква информация е много малка част от общия им брой (10^5/10^8 = 0.1%), а самият той е съвсем «поносимо» число. Следователно хеш-таблицата е наистина удачна.

 

 

Правим една хеш-таблица със 'статична' част от 100 000 (а може и повече) елемента. При всяка нова актуализация намираме двойката координати в таблицата и добавяме там. Аналогично четем финалните резултати при отговаряне на запитване.

 

 

Тестовете на задачата бяха ориентирани към 30т. за решения, сходни с 2), 60т. за такива, сходни с 3) и 100т. за такива, сходни с 4). Възможно е обаче поради малко по-либералния time-limit неоптимални решения да са взели 60 и повече точки.

 

 

Следва примерна реализация на четвърти подход на С.

 

/*

TASK:COL

LANG:C

*/

#include <stdio.h>

#include <stdlib.h>

 

#define MAXN 100010

#define MAXM 100010

typedef struct ssq ssq;

struct ssq {

       int x, y, z;

       ssq* next;

};

 

ssq sq[MAXM];

int f[MAXM];

int n,m;

 

int main () {

     int i, cd, a, b, c, cnt = 0; ssq *p;

 

     scanf("%d %d",&n,&m);

     for (i = 1; i <= n; i++) {

         scanf("%d %d %d",&a,&b,&c);

         cd = (a*b) % MAXM;

         if (!f[cd]) {

            sq[cd].x = a;  sq[cd].y = b;   sq[cd].z = c;

            f[cd] = 1;

            cnt++;

         } else {

            p = sq+cd;

            if (p->x == a && p->y == b) {

               p->z += c;

               continue;

            }

            while (p->next && ((p->next)->x != a || (p->next)->y != b))

                  p = p->next;

            if (!(p->next)) {

               p->next = (ssq *)malloc(sizeof(ssq));

               p = p->next;

               p->x = a;   p->y = b;    p->z = c;

               p->next = 0;

            } else {

              p = p->next;

              p->z += c;

            }

         }

     }

 

     for (i = 1; i <= m; i++) {

         scanf("%d %d",&a,&b);

         cd = (a*b) % MAXM;

         if (!f[cd]) {

            printf("0\n");

         } else {

           p = sq+cd;

           while (p && (p->x != a || p->y != b)) p = p->next;

           if (p) printf("%d\n",p->z);

           else   printf("0\n");

         }

     }

 

    return 0;

}

 

Николай Вълчанов, СМГ, valtchanov->mail.bg