0

I was recently working on the following problem. http://www.codechef.com/problems/D2

The Chef is planning a buffet for the DirectiPlex inauguration party, and everyone is invited. On their way in, each guest picks up a sheet of paper containing a random number (this number may be repeated). The guests then sit down on a round table with their friends. The Chef now decides that he would like to play a game. He asks you to pick a random person from your table and have them read their number out loud. Then, moving clockwise around the table, each person will read out their number. The goal is to find that set of numbers which forms an increasing subsequence. All people owning these numbers will be eligible for a lucky draw! One of the software developers is very excited about this prospect, and wants to maximize the number of people who are eligible for the lucky draw. So, he decides to write a program that decides who should read their number first so as to maximize the number of people that are eligible for the lucky draw. Can you beat him to it?

Input

The first line contains t, the number of test cases (about 15). Then t test cases follow. Each test case consists of two lines:

  1. The first line contains a number N, the number of guests invited to the party.
  2. The second line contains N numbers a1, a2, ..., an separated by spaces, which are the numbers written on the sheets of paper in clockwise order.

Output

For each test case, print a line containing a single number which is the maximum number of guests that can be eligible for participating the the lucky draw.

Constraints

1 ≤ N ≤ 10000 You may assume that each number number on the sheet of paper; ai is randomly generated, i.e. can be with equal probability any number from an interval [0,U], where U is some upper bound (1 ≤ U ≤ 106).

Example

Input:

3    
2    
0 0    
3    
3 2 1    
6    
4 8 6 1 5 2

Output:

1    
2    
4

On checking the solutions I found this code:

#include <iostream>
#include <vector>
#include <stdlib.h>
#include <algorithm>

#define LIMIT 37

using namespace std;

struct node {
    int val;
    int index;
};

int N;

int binary(int number, vector<int>& ans) {
    int start = 0;
    int n = ans.size();
    int end = n - 1;
    int mid;
    if (start == end)
        return 0;
    while (start != end) {
        mid = (start + end) / 2;
        if (ans[mid] == number)
            break;
        if (ans[mid] > number)
            end = mid;
        else
            start = mid + 1;
    }
    mid = (start + end) / 2;
    return mid;
}

void display(vector<int>& list) {
    cout << endl;
    for (int i = 0; i < list.size(); i++)
        cout << list[i] << " ";
    cout << endl;
}

int maxsubsequence(vector<int>& list) {
    vector<int> ans;
    int N = list.size();
    ans.push_back(list[0]);
    int i;
    // display(list);
    for (i = 1; i < N; i++) {
        int index = binary(list[i], ans);
        /*if(index+1<ans.size())
            continue;*/
        if (list[i] < ans[index])
            ans[index] = list[i];
        if (list[i] > ans[index])
            ans.push_back(list[i]);
        // display(ans);
    }
    return ans.size();
}

int compute(int index, int* g) {
    vector<int> list;
    list.push_back(g[index]);
    int itr = (index + 1) % N;
    while (itr != index) {
        list.push_back(g[itr]);
        itr = (itr + 1) % N;
    }
    return maxsubsequence(list);
}

int solve(int* g, vector<node> list) {
    int i;
    int ret = 1;
    for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
        // cout<<list[i].index<<endl;
        ret = max(ret, compute(list[i].index, g));
    }
    return ret;
}

bool cmp(const node& o1, const node& o2)
{ return (o1.val < o2.val); }

int g[10001];

int main() {
    int t;
    cin >> t;
    while (t--) {
        cin >> N;
        vector<node> list;
        int i;
        for (i = 0; i < N; i++) {
            node temp;
            cin >> g[i];
            temp.val = g[i];
            temp.index = i;
            list.push_back(temp);
        }
        sort(list.begin(), list.end(), cmp);
        cout << solve(g, list) << endl;
    }
    return 0;
}

Can someone explain this to me. I am well aware of calculating LIS in nlog(n). What I am not able to understand is this part:

int ret = 1;
for (i = 0; i < min(LIMIT, (int)list.size()); i++) {
    // cout<<list[i].index<<endl;
    ret = max(ret, compute(list[i].index, g));
}

and the reason behind sorting

sort(list.begin(),list.end(),cmp);
Siddharth
  • 9
  • 3
  • Am I missing something, or the sequence `4 8 6 1 5 2` should rather yield `3` as the output with the sequence `2 4 8`? – Utkan Gezer Sep 21 '14 at 20:34
  • @ThoAppelsin The LIS in this case is 1 2 4 8 – Ashu Pachauri Sep 21 '14 at 22:56
  • Correct. The LIS is 1 2 4 8. Starting from 1 and traversing the array. Since the numbers are arranged in a round table, you need to go back to start after reaching the end of the array. – Siddharth Sep 22 '14 at 06:37
  • How is it `1 2 4 8` when there is a `5` in between? If we are allowed to make such jumps (although I see nothing that implies we're allowed to do so), what are our constraints for it? If we have none, then why isn't the LIS simply `1 2 4 5 6 8` here, with 4 jumps? – Utkan Gezer Sep 24 '14 at 03:01
  • If you are starting with 1... Last element will be 6. You cant cross 1. – Siddharth Sep 30 '14 at 10:52

1 Answers1

0

This algorithm is simply guessing at the starting point and computing the LIS for each of these guesses.

The first value in a LIS is likely to be a small number, so this algorithm simply tries the LIMIT smallest values as potential starting points.

The sort function is used to identify the smallest values.

The for loop is used to check each starting point in turn.

WARNING

Note that this algorithm may fail for certain inputs. For example, consider the sequence

0,1,2,..,49,9900,9901,...,99999,50,51,52,...,9899

The algorithm will try just the first 37 starting points and miss the best starting point at 50.

You can test this by changing the code to:

int main() {
    int t;
    t=1;
    while (t--) {
    N=10000;
        vector<node> list;
        int i;
        for (i = 0; i < N; i++) {
            node temp;
        if (i<50)
        g[i]=i;
        else if (i<150)
            g[i]=9999-150+i;
        else
            g[i]=i-100;
            temp.val = g[i];
            temp.index = i;
            list.push_back(temp);
        }
        sort(list.begin(), list.end(), cmp);
        cout << solve(g, list) << endl;
    }
    return 0;
}

This will generate different answers depending on whether LIMIT is 37 or 370.

In practice, for randomly generated sequences it will have a good chance of working (although I don't know how to compute the probability exactly).

Peter de Rivaz
  • 33,126
  • 4
  • 46
  • 75