[Programming Question] Jingdong 2016 - Buy Candy

Posted by vijdev on Wed, 10 Jul 2019 01:08:15 +0200

Code writing is a bit cumbersome, welcome to correct~

Topic Source: Cyber Code Network
Buy candy (Beijing East 2016 intern real topic)

Topic Description

A candy company specializes in the production of children's candies. The most popular candies for children are A1 and A2, which are packaged in box. The volume of packaged A1 candy is one storage unit, while the volume of packaged A2 candy is exactly twice that of A1 candy.
These two kinds of candies are popular among children because they contain magic factors exclusively developed by the company. Candies in A1 or A2 sequences may appear to be packaged the same, but they are subdivided into different products because of their magic factor content.
Near the traditional festivals, the company's candy supply is in short supply. As a shrewd candy distributor, Xiao Dong hoped to make a lot of money, so he drove the truck with cash to pick up the goods. The capacity of the truck is determined. Xiaodong hopes to fill the truck with candy as much as possible, and the total content of the magic factor of candy is the highest. As long as it does not exceed the capacity of the truck, candy can always be loaded into the truck.

input

There are multiple sets of test data in the input. There are two integers n and v in the first row of each group of test data, 1 <= n <= 10 ^ 5, 1 <= v <= 10 ^ 9, n is the number of candies available, v is the capacity of the truck.
Then the specific information of N behavior candy, the first line number is 1, the second line number is 2, and so on, the last line number is n.
Each row contains two integers Ti and pi, 1<=ti<=2, 1<=pi<=10^4, ti is the sequence of candy, 1 is A1, 2 is A2, Pi is the magic factor content.

output

For each group of test data, the highest magic factor content in the candy that can be purchased is first output in a separate line.
Then, in a separate line, the candy numbers separated by spaces are output in the order of numbering from small to large.
If there are many groups of candy combinations can meet the requirements, the group with the smallest output number.
If no candy meets the requirement, output 0 in the first line and "No" in the second line.

thinking

The easy-to-enter misunderstanding is that the given interval is too large to be done in a general way. In fact, 10 ^ 9 is acceptable, and the maximum sum is 10 ^ 9 * 10 ^ 4 = 10 ^ 13, which can be calculated with long length. It is also acceptable to put 10 ^ 5 items in the queue.

There are only two types of numbers in this question, so the 01 knapsack method can not be used. Suppose we choose X candies numbered 1 and Y candies numbered 2.
Then X+2*Y<=v, i.e. two candies numbered 1 and one candy numbered 2 occupy the same volume. Either two candies numbered 1 or one candy numbered 2 are selected at a time.

specific working means
Two containers are used to store candy numbered 1 and candy numbered 2 respectively. The contents to be stored in the container include the index number of each candy, magic factor, and sorted according to magic factor. So consider using map < int, vector < int > to store (note: here we need to use vector to store the index number of each candy, because candy with the same magic factor may be mapped to multiple index numbers, although the title does not mention allowing duplication, but let alone not mention duplication, so we need to pay attention in the future. Repetitive factors, which are only realized when running test data.
Two maps were traversed according to magic factor from large to small, and two candy sum1 = Magic 1 + magic 2 with the highest magic factor was extracted from map No. 1 each time, and compared with one candy sum2 = Magic 3 with the highest magic factor in map No. 2. If sum1 > sum2, Magic 1 and Magic 2 are selected; if sum1 < sum2, Magic 3 is selected; if sum1= sum2, the relationship between the index numbers of the three is to be judged; if Magic 3 is the smallest, Magic 3 is selected; otherwise Magic 1 and Magic 2 are selected.
After a comparison, v-=2. It traverses to v==1 or v==0 in turn.
If v==0, output the result directly.
If v==1, there are two behaviors: one is to put a candy number 1 again, the other is to take out the candy number 1 which was last put in and replace it with the candy number 2.
So we need to make a judgment here!!! If there is candy Magic 1 in Number 1, record the candy prev of Number 1 last time, if Magic 1 + prev is larger than Number 2, select magic 1; if less than, choose candy of Number 2; if equal, judge the relationship between the three index numbers before and after making a decision.
Note: When v==1, we still need to make a judgment. Do not directly select candy No. 1 for filling!!

Code writing is a bit cumbersome, welcome to correct~

#include <iostream>
#include <map>
#include <queue>
#include <stack>
//
using namespace std;
typedef long long LL;
//
int main()
{
    int n;
    LL v;
    map<int, deque<int>>ones;//Storage No. 1 candy, where deque is used because the first two candies need to be extracted at a time
    //If you use queue, sometimes you need to pop one first to calculate the magic factor of the second candy.
    map<int, deque<int>>twos;//Storage Number 2 Candy
    priority_queue<int, vector<int>, greater<int>> result;//Store the index number of maxsum corresponding to the selected candy
    LL maxsum = 0;//Choose the sum of the maximum magic factors for candy
    //Note that if you put this CIN > n > m in, the local operation can be successful, but there has been a mistake on the Cyber Code Network.
    while (cin >> n >> v)
    {
        ones.clear();
        twos.clear();
        maxsum = 0;
        //Record input parameters
        int type, magic;
        int i = 1;
        while (i <= n && cin >> type >> magic)
        {
            if (type == 1)
            {
                ones[magic].push_back(i);
            }
            else if (type == 2)
            {
                twos[magic].push_back(i);
            }
            i++;
        }
        if (v < 1)
        {
            cout << 0 << endl << "No" << endl;
            continue;
        }
        map<int, deque<int>>::reverse_iterator oneindex1 = ones.rbegin();
        map<int, deque<int>>::reverse_iterator oneindex2 = ones.rbegin();
        //Note that you need to determine if one is empty and that using rend()++ will cause errors.
        if (oneindex1 != ones.rend() && (oneindex1->second).size() == 1) oneindex2++;
        map<int, deque<int>>::reverse_iterator twoindex = twos.rbegin();
        LL num = v;
        //You need to record the magic value of the candy with the last selected number 1 and the corresponding index number.
        int prev[2] = { 0, 0 };
        while (num > 1)
        {
            //Case 1: One has at least two values and twos has at least one value
            if (oneindex2 != ones.rend() && twoindex != twos.rend())
            {
                bool isOneMove = true;
                LL sum = oneindex1->first + oneindex2->first;
                if (sum > twoindex->first) isOneMove = true;
                else if (sum < twoindex->first) isOneMove = false;
                else if (sum == twoindex->first)
                {
                    //Compare who is ahead
                    //If two indexes are in the same vector, the index number of oneindex 2 should be extracted specially.
                    if (oneindex1->second.front() == oneindex2->second.front())
                    {
                        int index2 = oneindex1->second[1];
                        if (index2 > twoindex->second[0]) isOneMove = false;
                    }
                    else if (oneindex1->second.front() > twoindex->second.front() 
                                || oneindex2->second.front() > twoindex->second.front())
                        isOneMove = false;
                }
                if (isOneMove)//Select oneindex1 and oneindex2
                {                   
                    maxsum += sum;//Add sum to sum                    
                    //Add these two to result
                    result.push(oneindex1->second.front());
                    oneindex1->second.pop_front();
                    //Record the magic value of candy No. 1 selected last time and the corresponding index number
                    prev[0] = oneindex2->first;
                    prev[1] = oneindex2->second.front();
                    result.push(oneindex2->second.front());
                    oneindex2->second.pop_front();
                    //Shift oneindex1 and oneindex2
                    if (oneindex2->second.size() >= 2)
                    {
                        //At this point oneindex 2 must not change
                        //Determine whether oneindex 1 needs one
                        if (oneindex1->second.size() == 0)
                            oneindex1++;
                    }
                    else if (oneindex2->second.size() == 1)
                    {
                        if (oneindex1->second.size() == 0)
                            oneindex1++;
                        oneindex2++;
                    }
                    else if (oneindex2->second.size() == 0)
                    {
                        oneindex2++;
                        if (oneindex2 != ones.rend() && oneindex2->second.size() == 1)
                            oneindex2++;
                        while (oneindex1 != ones.rend() && oneindex1->second.size() == 0)
                            oneindex1++;
                    }
                }
                else//Select twoindex
                {
                    maxsum += twoindex->first;
                    result.push(twoindex->second[0]);
                    twoindex->second.erase(twoindex->second.begin());
                    if (twoindex->second.size() == 0)
                        twoindex++;
                }
                num -= 2;//Capacity reduction 2
            }
            //Add only oneindex1 and oneindex2
            else if (oneindex2 != ones.rend() && twoindex == twos.rend())
            {
                LL sum = oneindex1->first + oneindex2->first;
                maxsum += sum;
                num -= 2;
                result.push(oneindex1->second.front());
                oneindex1->second.pop_front();
                prev[0] = oneindex2->first;
                prev[1] = oneindex2->second.front();
                result.push(oneindex2->second.front());
                oneindex2->second.pop_front();
                if (oneindex2->second.size() >= 2)
                {
                    if (oneindex1->second.size() == 0)
                        oneindex1++;
                }
                else if (oneindex2->second.size() == 1)
                {
                    if (oneindex1->second.size() == 0)
                        oneindex1++;
                    oneindex2++;
                }
                else if (oneindex2->second.size() == 0)
                {
                    oneindex2++;
                    if (oneindex2 != ones.rend() && oneindex2->second.size() == 1)
                        oneindex2++;
                    while (oneindex1 != ones.rend() && oneindex1->second.size() == 0)
                        oneindex1++;
                }
            }
            else if (oneindex2 == ones.rend() && twoindex != twos.rend())
            {
                bool isOneMove = false;
                if (oneindex1 != ones.rend())
                {
                    //There is only one in one, compared with two, which is equivalent to one index 2 0.                   
                    if (oneindex1->first > twoindex->first) isOneMove = true;
                    else if (oneindex1->first < twoindex->first) isOneMove = false;
                    else if (oneindex1->first == twoindex->first)
                    {
                        //Compare the index size of the two
                        if (oneindex1->second < twoindex->second) isOneMove = true;
                        else isOneMove = false;
                    }
                }
                if (isOneMove)
                {
                    maxsum += oneindex1->first;
                    num--;
                    result.push(oneindex1->second.front());
                    prev[0] = oneindex1->first;
                    prev[1] = oneindex1->second.front();
                    oneindex1->second.erase(oneindex1->second.begin());
                    if (oneindex1->second.size() == 0)
                        oneindex1++;
                }
                else
                {
                    maxsum += twoindex->first;
                    num -= 2;
                    result.push(twoindex->second.front());
                    twoindex->second.erase(twoindex->second.begin());
                    if (twoindex->second.size() == 0)
                        twoindex++;
                }
            }
            else if (oneindex2 == ones.rend() && twoindex == twos.rend())
            {
                //There's only one left
                while (num > 1 && oneindex1 != ones.rend())
                {
                    maxsum += oneindex1->first;
                    num--;
                    result.push(oneindex1->second.front());
                    prev[0] = oneindex1->first;
                    prev[1] = oneindex1->second.front();
                    oneindex1->second.pop_front();
                    if (oneindex1->second.size() == 0)
                        oneindex1++;
                }
                break;
            }
        }
        if (num == 1 && oneindex1 != ones.rend())
        {
            bool isUndo = false;
            if (twoindex != twos.rend())
            {
                int sum = oneindex1->first + prev[0];
                if (sum < twoindex->first) isUndo = true;
                else if (sum == twoindex->first)
                {
                    //Judging the Index Size of the Three
                    if (oneindex1->second[0] > twoindex->second[0] 
                        || prev[1] > twoindex->second[0])
                        isUndo = true;
                }
            }
            if (isUndo)
            {
                if (prev[0] != 0)
                {
                    //Exclude oneindex 2 and select twoindex
                    maxsum = maxsum - prev[0] + twoindex->first;
                    stack<int>temp;
                    while (result.top() != prev[1])
                    {
                        temp.push(result.top());
                        result.pop();
                    }
                    result.pop();
                    while (!temp.empty())
                    {
                        result.push(temp.top());
                        temp.pop();
                    }
                    result.push(twoindex->second[0]);
                }
            }
            else//Still choose 1
            {
                maxsum += oneindex1->first;
                result.push(oneindex1->second[0]);
            }
            num--;
        }
        else if (num == 1 && oneindex1 == ones.rend())
        {
            bool isUndo = false;
            if (twoindex != twos.rend())
            {
                int sum = prev[0];
                if (sum < twoindex->first) isUndo = true;
                else if (sum == twoindex->first)
                {
                    //Judge who is ahead
                    if (prev[1] > twoindex->second[0])
                        isUndo = true;
                }
            }
            if (isUndo)
            {
                if (prev[1] != 0)
                {
                    //Exclude oneindex 2 and select twoindex
                    maxsum = maxsum - prev[0] + twoindex->first;
                    stack<int>temp;
                    while (result.top() != prev[1])
                    {
                        temp.push(result.top());
                        result.pop();
                    }
                    result.pop();
                    while (!temp.empty())
                    {
                        result.push(temp.top());
                        temp.pop();
                    }
                    result.push(twoindex->second[0]);
                }
            }
            else if (oneindex1 != ones.rend())
            {
                maxsum += oneindex1->first;
                result.push(oneindex1->second[0]);
            }
            num--;
        }
        if (maxsum > 0)
            cout << maxsum << endl;
        else
            cout << 0 << endl << "No" << endl;
        while (!result.empty())
        {
            cout << result.top() << endl;
            result.pop();
        }
    }
    return 0;
}

Topics: network less