Untitled

mail@pastecode.io avatar
unknown
plain_text
a year ago
14 kB
3
Indexable
Never
[Problem Description]

The last bastion of humanity – < Survival Train >
The extreme weather condition froze everything on the Earth. One train is relentlessly travelling.

Humanity’s last survivors are on the train.

The train is far from upholding equality. The tail section of the train is where cold, hunger, and dirt prevail while the head car is of comfort and luxury.

 

The closer to the head of train, the better the condition.

All passengers hope to move car-by-car up toward the front of the train.

In order to go there, there is no other way but to save money diligently.

N passengers are aboard. There are M passengers each in N/M train sections. (N is a multiple of M).  

Each passenger will receive their own Passenger ID whose value is from 0 to N-1.

In the very first train section, Passenger IDs from 0 to M-1 are aboard.

In the second train section, Passenger IDs from M to 2M-1 are aboard.

Like the order above, passengers are aboard until the last section, the tail section of the train.

All passengers have jobs and accounts managing points that are used like money.

Points earned individually and through one’s job and points that have to be paid are calculated and reflected in the passengers’ accounts frequently.

Passengers with many points move up toward the section in front while passengers with few points move back to the section behind.

 

Implement each required function by referring to the following API description.

※ The function signature below is based on C/C++. As for other languages, refer to the provided Main and User Code.

 

The following is the description of API to be written in the User Code.

void init(int N, int M, int J, int mPoint[], int mJobID[])

This function is called in the beginning of each test case.

There are N passengers. In a group of M, each group is aboard in N / M sections. N is a multiple of M.

Passenger ID is given in order from 0 to N-1. Starting from passengers with small ID value, M passengers each get on to the front part of the train.  

mPoint[] is the number of points possessed by a passenger. mJobID[] is the job of a passenger.

There are J types of job. Job ID is from 0 to J-1.

The information of Passenger ID 0 are mPoint[0] and mJobID[0]. The information of Passenger ID 1 are mPoint[1] and mJobID[1]. The information of passengers until Passenger ID N-1 are given in order.

The maximum number of people by job does NOT exceed 200.

 

__Parameters

_____N : The number of passengers (21 ≤ N ≤ 100,000)

_____M : The number of passengers in one section (7 ≤ M ≤ 10,000 and 2 ≤ N / M ≤ 10)

_____J : The number of types of job (1 ≤ J ≤ 1000)

_____mPoint : The number of points possessed by each passenger ( 0 ≤ mPoint[] ≤ 10,000)

_____mJobID : The Job ID of passenger (0 ≤ mJobID[] ≤ J - 1)

void destroy()

This function is called at the end of each test case.

Even if the function is left empty, this does not affect the grading.   

int update(int mID, int mPoint)

This function reflects mPoint in the account of the passenger whose ID is mID.

When mPoint is a positive number, it means that the number of the passenger’s points increased. When it is a negative number, it means that the number of the points decreased.

After reflecting the number of points, this function returns the number of the passenger’s points whose ID is mID.

It is guaranteed that the number of points possessed by Passenger mID is within the range of -1,000,000,000 to 1,000,000,000.

 

__Parameters

_____mID : The Passenger ID (0 ≤ mID ≤ N-1)

_____mPoint : The number of points reflected in an account ( -1,000 ≤ mPoint ≤ 1,000 )

__Returns

_____The point earned by a passenger

int updateByJob(int mJobID, int mPoint)

This function reflects mPoint in accounts of all passengers whose Job ID is mJobID.

When mPoint is a positive number, it means that the number of the passenger’s points increased. When it is a negative number, it means that the number of points decreased.

After reflecting the number of points, this function returns the sum of points possessed by passengers whose Job ID is mJobID.

It is guaranteed that the sum of points possessed by passengers whose Job ID is mJobID is within the range of -1,000,000,000 to 1,000,000,000.

 

__Parameters

_____mJobID : The Job ID (0 ≤ mJobID ≤ J - 1)

_____mPoint : The number of points reflected in an account ( -1,000 ≤ mPoint ≤ 1,000 )

 

__Returns

_____ The sum of points possessed by passengers whose Job ID is mJobID

int move(int mNum)

From the biggest points to the smallest points by train section, this function selects the top mNum and bottom mNum passengers.

When the number of points is the same, the passenger whose ID is smaller is ranked higher.

As there are no train section in front of the very first section, this function does NOT select the top mNum passengers.

As there are no train section behind the tail section, this function does NOT select the bottom mNum passengers.

After the selection, the top nNum passengers in each section move to the section in front, while the bottom nNum passengers in each section move to the section behind.

This function returns the sum of points possessed by the passengers who moved.

When selecting the top mNum and bottom mNum passengers in one section, there is NO case when the passengers overlap.

It is guaranteed that the sum of points possessed by the passengers who moved is within the range of -1,000,000,000 to 1,000,000,000.

 

__Parameters

_____mNum : The number of passengers to move by section ( 1 ≤ mNum ≤ 5, mNum * 2 ≤ M )

 

__Returns

_____ The sum of points possessed by the passengers who moved

 

[Example]

Let’s look into a case where functions are called as below.

#

Function

Description

Return

1

init(21,7,3,
{8,19,18,9,…...},
{2,0,2,1,…...})

There are 21 passengers. In a group of 7, they are in 3 sections.

There are 3 types of job in the train.

 

2

move(2)

After selecting the top 2 and bottom 2 by section,  
the top 2 are brought to the section in front, while the bottom 2 are sent to the section behind.

75

3

move(2)

 

73

4

move(2)

 

68

5

update(2,796)

Passenger ID 2 earned 796 points.

814

6

updateByJob(0,-686)

Passengers of Job ID 0 all spent 686 points.

-5394

7

move(1)

 

-1330

8

update(17,-275)

 

-273

9

update(11,364)

 

-304

10

update(14,-76)

 

-76

11

move(2)

 

-2667

12

update(9,-172)

 

-171

13

update(1,-970)

 

-1637

14

update(11,207)

 

-97

15

move(1)

 

-1804

16

update(16,-690)

 

-1367

17

updateByJob(2,471)

 

3029

18

updateByJob(1,-649)

 

-5498

19

move(2)

 	
-2677

20

move(2)

 

-4310

21

move(2)

 

-4707

22

update(2,-890)

 

395

23

move(1)

 

-2082

24

update(20,139)

 

-546

25

updateByJob(2,59)

 

2434

26

update(9,-589)

 

-230

 

The table below shows the status after executing each function.

The table with 2 rows shows the status before and after a movement.  

The points possessed by passengers colored in red mean that they are negative numbers.







 

[Constraints]

1. For each test case, init() is called in the beginning and destroy() is called at the end.

2. For each test case, update() is called up to 10,000 times.

3. For each test case, updateByJob() is called up to 300 times.

4. For each test case, move() is called up to 1,000 times.

5. For each test case, the maximum number of people by job does NOT exceed 200.

 

[Input and Output]

As the input and output are processed in the provided code in the Main, they are not processed separately in the User Code.

The output result for the sample input is in the format of “#TC number result.” It is the correct answer if the result is 100; it is the wrong answer if it is 0.


#define MAX_N 100000
#define MAX_J 1000
#define opt __attribute((optimize("Ofast")))
 
int sectionNums;
 
struct Passengers {
   public:
    unsigned int id;
    int point;
    unsigned int Section;
    unsigned int minId, maxId;
    opt bool operator<(Passengers& mP) const {
        if (this->point != mP.point)
            return this->point < mP.point;
        else
            return this->id > mP.id;
    }
} passengers[MAX_N];
 
struct Heap {
   public:
    int idList[14286];
    bool isMaxHeap;
    unsigned int size;
    opt void initMaxHeap() {
        this->isMaxHeap = true;
        this->size = 0;
    }
    opt void initMinHeap() {
        this->isMaxHeap = false;
        this->size = 0;
    }
    opt void insert(int index) {
        this->idList[this->size] = index;
        if (isMaxHeap)
            passengers[index].maxId = size;
        else
            passengers[index].minId = size;
        heapifyUp(this->size++);
    }
    opt void heapifyUp(int index) {
        int indx = index;
        int parent = (indx - 1) / 2 ;
        if (parent>= 0) {
            if (comp(parent, indx) == isMaxHeap)
                indx = parent;
        }
        if (indx != index) {
            Swap(indx, index);
            heapifyUp(indx);
        }
    }
    opt void heapifyDown(int index) {
        int indx = index,
        left = 2 * indx + 1,
        right = 2 * indx + 2;
        if (left < size) {
            if (comp(indx, left) == isMaxHeap)
                indx = left;
        }
        if (right < size) {
            if (comp(indx, right) == isMaxHeap)
                indx = right;
        }
        if (indx != index) {
            Swap(indx, index);
            heapifyDown(indx);
        }
    }
    opt void erase(int index) {
        Swap(index, --this->size);
        heapifyDown(index);
        heapifyUp(index);
    }
    opt void update(int index) {
        heapifyUp(index);
        heapifyDown(index);
    }
    opt int pop() {
        Swap(0, --this->size);
        heapifyDown(0);
        return this->idList[this->size];
    }
    opt void Swap(int a, int b) {
        int t = idList[a];
        idList[a] = idList[b];
        idList[b] = t;
        if (isMaxHeap) {
            passengers[idList[a]].maxId = a;
            passengers[idList[b]].maxId = b;
        } else {
            passengers[idList[a]].minId = a;
            passengers[idList[b]].minId = b;
        }
    }
    opt bool comp(int id1, int id2) {
        return passengers[idList[id1]] < passengers[idList[id2]];
    }
} Max[10], Min[10];
 
struct JobList {
   public:
    int idList[200];
    int size;
    opt void reset() {
        size = 0;
    }
    opt void push(int id) {
        idList[size++] = id;
    }
    opt int update(int point) {
        int sum = 0;
        for (register int i = 0; i < size; i++) {
            passengers[idList[i]].point += point;
            Min[passengers[idList[i]].Section].update(passengers[idList[i]].minId);
            Max[passengers[idList[i]].Section].update(passengers[idList[i]].maxId);
            sum += passengers[idList[i]].point;
        }
        return sum;
    }
} jobList[MAX_J];
 
opt void init(int N, int M, int J, int mPoint[], int mJobID[]) {
    sectionNums = N / M;
    for (register int i = 0; i < sectionNums; i++) {
        Min[i].initMinHeap();
        Max[i].initMaxHeap();
    }
    for (register int i = 0; i < J; i++)
        jobList[i].reset();
    for (register int i = 0; i < N; i++) {
        passengers[i].id = i;
        passengers[i].point = mPoint[i];
        passengers[i].Section = i / M;
        jobList[mJobID[i]].push(i);
        Max[i / M].insert(i);
        Min[i / M].insert(i);
    }
}
 
void destroy() {
}
 
opt int update(int mID, int mPoint) {  // 10.000
    passengers[mID].point += mPoint;
    Max[passengers[mID].Section].update(passengers[mID].maxId);
    Min[passengers[mID].Section].update(passengers[mID].minId);
    return passengers[mID].point;
}
 
opt int updateByJob(int mJobID, int mPoint) {  // 300
    return jobList[mJobID].update(mPoint);
}
 
int t, toFront[10][5], toBack[10][5];
opt int move(int mNum) {  // 1.000
    int sum = 0;
    for (register int s = 0; s < sectionNums - 1; s++) {
        for (register int i = 0; i < mNum; i++) {
            t = Min[s].pop();
            Max[s].erase(passengers[t].maxId);
            sum += passengers[t].point;
            ++passengers[t].Section;
            toBack[s][i] = t;
        }
    }
    for (register int s = 1; s < sectionNums; s++) {
        for (register int i = 0; i < mNum; i++) {
            t = Max[s].pop();
            Min[s].erase(passengers[t].minId);
            sum += passengers[t].point;
            --passengers[t].Section;
            toFront[s][i] = t;
        }
    }
    for (register int s = 0; s < sectionNums; s++) {
        for (register int i = 0; i < mNum; i++) {
            if (s > 0) {
                Min[s - 1].insert(toFront[s][i]);
                Max[s - 1].insert(toFront[s][i]);
            }
            if (s < sectionNums - 1) {
                Min[s + 1].insert(toBack[s][i]);
                Max[s + 1].insert(toBack[s][i]);
            }
        }
    }
    return sum;
}