daihan's blog

By daihan, 8 years ago, In English

Hello codeforces community , problem ZigZag array is for distinct data , I solved this problem . But if data are duplicate(same data occur several times) problem become very complex . There has many corner case :

11

2 4 6 8 9 11 10 8 5 3 1

=>2 8 8 1 ( solution 1, remove 7 numbers)

=>2 11 1 (solution 2, remove 8 numbers)

so ans is 7

10

1 2 3 4 7 8 9 7 6 4

=>1 4 4 (solution 1, remove 7 numbers)

=>1 7 7 4 (solution 2, remove 6 numbers)

=>1 9 4 (solution 3, remove 7 numbers)

so ans is 6

6

1 2 3 4 5 4

=>1 4 4 (solution 1, remove 3 numbers)

=>1 5 4 (solution 2, remove 3 numbers)

so ans is 3

5

1 2 3 2 1

=>1 2 2 1 (solution 1, remove 1 number)

=>1 3 1 (solution 2,remove 2 numbers)

so ans is 1

If 1<=n<=10^5 , How to solve this problem ? and how to implement it efficiently ? I implement it but code become very complex : https://pastebin.com/QrhWgdEj

  • Vote: I like it
  • -3
  • Vote: I do not like it

| Write comment?
»
8 years ago, # |
Rev. 11   Vote: I like it +18 Vote: I do not like it

You are not using DP on this problem, but you can solve simply with using DP in O(n2) (because n ≤ 100). First, the problem is asking "minimum number of deletion", but it is same value to n — "maximum length of zigzag subsequence". Second, let dp[i][0] = "the maximum length of subsequence that ends in i and satisfying (the second element from the last) > (the last element), and dp[i][1] is almost same definition but (the second last) < (the last). And, the DP relation is: dp[i][0] = max(1, maxj < i, a[j] > a[i]{dp[j][1] + 1}), and dp[i][1] = max(1, maxj < i, a[j] < a[i]{dp[j][0] + 1}). Finally the answer is n - max(dp[n - 1][0], dp[n - 1][1]). My code is here (16-line in C++)
This is a main idea, but if the array has same values, you have to add dp[i][2] for equal and change DP relation a little.
EDIT: It's n ≤ 100 (real contest constraints) solution (It's O(n2) and of course if n ≤ 10000 you can solve it). I know you edited the blog and changed the constraints to n ≤ 100000.

  • »
    »
    8 years ago, # ^ |
    Rev. 2   Vote: I like it -13 Vote: I do not like it

    Your code complexity is n*(n+1)/2 = O(n^2) . If n is large 10^5 . How to do it more efficiently ?

    • »
      »
      »
      8 years ago, # ^ |
        Vote: I like it +5 Vote: I do not like it

      It can be optimised with two segment trees.

      • »
        »
        »
        »
        8 years ago, # ^ |
        Rev. 2   Vote: I like it -18 Vote: I do not like it

        [blank]

        • »
          »
          »
          »
          »
          8 years ago, # ^ |
            Vote: I like it +5 Vote: I do not like it

          It's similar to counting lis(longest increasing sequence) with segment tree.

          • »
            »
            »
            »
            »
            »
            8 years ago, # ^ |
              Vote: I like it +5 Vote: I do not like it

            I think your counting LIS algorithm is "sort p[i] = pair(a[i], i) in increasing order, and calculate like dpp[i].second = min(dp0, dp1, ..., dpp[i].second - 1) + 1. (If I'm wrong, I'm sorry) If so, I think the technique can't use because you have to calculate in decreasing order for dp[i][0], and increasing order for dp[i][1]. But dp[i][0] uses dp[i][1] value, and vice versa. How to calculate it?

            • »
              »
              »
              »
              »
              »
              »
              8 years ago, # ^ |
              Rev. 3   Vote: I like it +5 Vote: I do not like it

              Compress numbers in the input so everything is in range [1, n]. Now our dp is dp[x][0,1] = length of sequence with last number x, because we process indexes in increasing order. It can be calculated fast with two segment trees. Is it wrong?

»
8 years ago, # |
  Vote: I like it +11 Vote: I do not like it
just check left & right of the vector if somewhere condition will true.

#include <bits/stdc++.h>
using namespace std;

vector<int>v;

bool solve(int x, int y, int z)
{
    if(x >= v.size() || y >= v.size() || z >= v.size() || !x || !y || !z)
        return false;
    if( v[x] > v[y] && v[y] > v[z] )
        return true;
    if( v[x] < v[y] && v[y] < v[z] )
        return true;
    return false;
}

int main()
{
    int n, i, x, cnt=0;
    cin >> n;

    v.push_back(0);

    for(i=1; i<=n; i++)
    {
        cin >> x;
        v.push_back(x);
    }
    for(i=1; i<=v.size()-2; i++)
    {
        if( solve(i, i+1, i+2) && v.size() >= 3 )
        {
            cnt++;
            if( solve(i+1, i+2, i+3) )
                v.erase(v.begin()+i+2);
            else if( solve(i-1, i, i+1) )
                v.erase(v.begin()+i);
            else
                v.erase(v.begin()+i+1);
            i--;
        }
    }
    cout << cnt << endl;
    return 0;
}
  • »
    »
    8 years ago, # ^ |
    Rev. 6   Vote: I like it +8 Vote: I do not like it

    It is still O(n2), but if your approach is correct, it seems that you can solve in O(nlogn) with std::set.
    Any proof of your solution is correct?
    EDIT: Mr_Emrul, I want to know whether your solution is correct (+proof) if the element of array is not necessarily distinct.
    EDIT 2: daihan hacked so this is a wrong solution.

    • »
      »
      »
      8 years ago, # ^ |
        Vote: I like it -15 Vote: I do not like it

      My solution in HR

      If you can not see (not public) then I will give you screenshot.

    • »
      »
      »
      8 years ago, # ^ |
      Rev. 2   Vote: I like it -15 Vote: I do not like it

      square1001 can you give me a test case? please :) then i will test it

      • »
        »
        »
        »
        8 years ago, # ^ |
        Rev. 2   Vote: I like it +4 Vote: I do not like it

        You are not answering my question. Of course I know your code and already tested my few tricky cases and got a correct value. I only want to know why your solution is correct. If you can, please give me a mathematical explanation.

        • »
          »
          »
          »
          »
          8 years ago, # ^ |
            Vote: I like it 0 Vote: I do not like it

          You wanted to know whether my solution is correct or not. You didn't asked my why my code is correct.

        • »
          »
          »
          »
          »
          8 years ago, # ^ |
            Vote: I like it 0 Vote: I do not like it

          square1001, for giving proof to you, I definitely need a test case from you, needn't I?

          • »
            »
            »
            »
            »
            »
            8 years ago, # ^ |
              Vote: I like it 0 Vote: I do not like it

            your code not for duplicate data .

            • »
              »
              »
              »
              »
              »
              »
              8 years ago, # ^ |
                Vote: I like it 0 Vote: I do not like it

              please give me a test case, which give wrong output for my code.

              • »
                »
                »
                »
                »
                »
                »
                »
                8 years ago, # ^ |
                Rev. 2   Vote: I like it +6 Vote: I do not like it

                10

                1 2 3 4 7 8 9 7 6 4

                =>1 4 4 (removed 7 numbers)

                =>1 7 7 4 (removed 6 numbers)

                =>1 9 4 (removed 7 numbers)

                ans should be 6 . Your code gives 7 .