Thread: Need optimization

  1. #1
    Registered User
    Join Date
    Nov 2018
    Posts
    32

    Need optimization

    Problem:

    We have an array of N elements(size upto 10^5) and We need to have q queries(upto 10^5) , of type:
    !-> right rotate the array
    ?-> print maximum consecutive ones in the array <=k(k is an upperbound, if we find maximum consecutive ones >k print k)

    Array elements are only of type 0's and 1's,

    My code times out (time limit 1sec) for the constraints mentioned, lease tell me some better approach or optimization for this code :

    Example input:
    5 5 3
    1 1 0 1 1
    ?!?!?
    Example output:
    2
    3
    3
    Code:
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    
    typedef vector<int> vi
    
    
    
    
    vi rrot(vi vec, int k, int n) 
    { 
        k %= n;
        k = n-k;
        rotate(vec.begin(), vec.begin()+k,vec.end());
        return vec;
    } 
    
    
    int findone(vi nums,int k) {
            vi result;
            vi zero_index;
            for (int i=0;i<nums.size();i++)
            {
                if (nums[i]==0)
                    zero_index.push_back(i);
            }
            zero_index.insert(zero_index.begin(),-1);
            zero_index.push_back(nums.size());
            
            for(int i=0;i<zero_index.size()-1;i++)
            {
                result.push_back(zero_index[i+1]-zero_index[i]-1);
            }
            int val= *max_element(result.begin(),result.end());  
            if(val<k) return val;
            return k;
        }
    
    
    int main() {
    
    
    
    
            LL n,q,k;cin>>n>>q>>k;  //n is length of sequence of 1s and 0s , q is number of queries k is upperbound to max ones
            vi arr(n); 
        
            for(int i=0;i<n;i++) {cin>>arr[i];} 
        
            vi queries; 
            string quer;cin>>quer;  //input quer string
            int c=0;
            //ALGO: Basically stored consecutive '!' to get a number of jumps neede to make before '?' query, this one rather doing one by one rotations I can simply rotate to 'c' jumps
            for(int i=0;i<quer.length();)
            {
                while(quer[i]=='!')
                {
                    c++;i++;
                }
    
    
                queries.push_back(c);
                i++;
            }
    
    
            for(int i=0;i<queries.size();i++)
            {   
                vector<int> temp=arr; //get original array and store in temporary
                temp=rrot(temp,queries[i],n);  
                cout<<findone(temp,k)<<"\n";  //print result... 
            }
    
    
        return 0;
    }

  2. #2
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    I find k a little strange. I wonder what it's purpose is? Is it's limit also 10^5?

    Anyway, the first thing you might do is to not rotate the array at all. Just keep an index (iterator/pointer/whatever) to the current "first" element. This also obviates the need to copy the array over and over for all the queries. Now you can just set the index back to 0.

    Also, I notice that you are passing the vector by value so that it's copied. You should pass by reference. I'll post a rewrite of your code in a few minutes.

    And shouldn't you be re-setting c to zero in your input loop? I don't think you want the total cummulative number of !'s, but just the latest streak.
    Last edited by john.c; 11-09-2018 at 04:13 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  3. #3
    Registered User
    Join Date
    Nov 2018
    Posts
    32
    Yes k has a limit of 10^5.

    ok, but, what about the consecutive ones, how to calculate them, after not rotating the array?? should I run a loop from the current till i reaches max size, then set i back to 0 till, the current-1 ??

    I tried passing by reference, I was still getting over time limit(sorry this code was not the latest, only this had comments in it )
    regarding c, no am, just taking the whole value uptill the ith '?' and rotating the original array by that much step, notice how I give temp=arr for each loop..

    I'll try the not rotating idea and show you the code.
    Last edited by sc7; 11-09-2018 at 04:23 PM.

  4. #4
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Also, you are copying arr to temp so that each set of rotations will always start from the first configuration. But that's not how I interpret the problem. I think each set of rotations is supposed to start where the previous ones have left off. Still, this is just a "correctness" fix, not a performance fix.

    EDIT: I can't comprehend your findones routine but it's hard to believe it's any faster than just searching though the vector.
    Last edited by john.c; 11-09-2018 at 04:31 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  5. #5
    Registered User
    Join Date
    Nov 2018
    Posts
    32
    here's the code that I came up with after your comments(this is giving wrong answer to the problem though, also it's still timing out on big input) ,maybe i did something wrong
    Code:
    #include <bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    
    
    typedef vector<int> vi;
    
    
    int max_ones(vector<int> arr,int curr,int k)
    {   
        int res=-1;int n=arr.size();
    
    
        for(int i=curr;i<n;)
        {
            int c=0;
            while(arr[i]==1)
            {
                c++;i++;
                if(i==n)
                {
                    for(int j=0;j<curr;)
                    {
                        while(arr[j]==1)
                            {c++;j++;}
                        if(c>res) res=c;
                        c=0;j++;
                    }
                }
            }
    
    
                if(c>res) res=c;
                i++;
        }
        if(res<=k) return res;
        return k;
    }
    
    
    int main() {
    
    
    
    
        #ifndef ONLINE_JUDGE
            freopen("inp.txt", "r", stdin);
            freopen("output.txt","w", stdout);
        #endif
            LL n,q,k;cin>>n>>q>>k;  //n is length of sequence of 1s and 0s , q is number of queries k is upperbound to max ones
            vi arr(n); 
        
            for(int i=0;i<n;i++) {cin>>arr[i];} 
            int current=0;
            vi queries; 
            string quer;cin>>quer;  //input quer string
            int c=0;
           
            for(int i=0;i<quer.length();i++)
            {
                if(quer[i]=='!')
                {
                    current++;
                    if(current>=n)
                        current=current%n;
                }
                else if(quer[i]=='?')
                {
                    cout<<max_ones(arr,current,k)<<"\n";
                }
    
    
            }
    
    
        return 0;
    }
    Is there any efficient way to get maximum number of ones ? I don't see any better than O(n) ???
    Last edited by sc7; 11-09-2018 at 04:42 PM.

  6. #6
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Consider:
    0110011111011100

    The maximum number of 1's is 5. No matter how it's rotated the maximum (possible) will be 5. However, it's possible for it to be rotated in such a way that the max is less than 5. Here is is rotated 7 positions right, now the max is 3.
    1101110001100111

    Since you are dealing with a single sequence of 1's and 0's read at the beginning of the program upon which you perform a large number of queries, some preprocessing may be fruitful. I'm not sure exactly what, though.

    As for counting the max consecutive 1's, this is the simple way to do it. But I think you need something better. Note that I've passed the vector by reference! That's important, although it's not going to speed it up that much.
    Code:
    int findone(vi &nums, int first, int k) {
        int high = 0, cnt = 0;
        int i = first;
        do {
            if (nums[i])
                ++cnt;
            else {
                if (cnt > high)
                    high = cnt;
                cnt = 0;
            }
            i = (i + 1) % nums.size();
        } while (i != first);
        return high < k ? high : k;
    }
    Still, that k bugs me. It smells like a hint....
    A little inaccuracy saves tons of explanation. - H.H. Munro

  7. #7
    Registered User
    Join Date
    Nov 2018
    Posts
    32
    your code is giving the wrong output, I don't know what, but I think its the i=(i+1)%num.size() that's doing something wrong?

    input:
    5 7 3
    1 1 0 1 1
    ?!?!?!?

    output:
    2
    1
    0
    3

    expected:
    2
    3
    3
    3

    what kind of preprocessing though ??

  8. #8
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Yeah, I didn't even try compiling it. I needed to check for a new high once more after the loop.
    However, I think you may be "rotating" in the wrong direction, too, passing in the wrong input.
    Rotating to the right moves the "first" element index backwards.
    Code:
    #include <bits/stdc++.h>
    using namespace std;
     
    int findone(vector<int> &nums, int first, int k) {
        int high = 0, cnt = 0;
        int i = first;
        do {
            if (nums[i])
                ++cnt;
            else {
                if (cnt > high)
                    high = cnt;
                cnt = 0;
            }
            i = (i + 1) % nums.size();
        } while (i != first);
        if (cnt > high) high = cnt;
        return high < k ? high : k;
    }
     
    int main() {
        cin.sync_with_stdio(false);
        cin.tie(nullptr);
     
        int n; // length of sequence of 1s and 0s
        int q; // number of queries
        int k; // upperbound to max ones
        cin >> n >> q >> k;
     
        vector<int> arr(n);
        for (int i = 0; i < n; i++)
            cin >> arr[i]; 
     
        int first = 0;
        char ch;
        for (int i = 0; i < q; i++) {
            cin >> ch;
            if (ch == '!') {
                if (--first < 0)
                    first = arr.size() - 1;
            }
            else
                cout << findone(arr, first, k) << '\n';
        }
    }
    Last edited by john.c; 11-09-2018 at 05:40 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  9. #9
    Registered User
    Join Date
    Nov 2018
    Posts
    32
    Time limit is exceeding in it.
    I think, the approach should be changed, not rotating the array was a good start for performance but calculating max 1's each time maybe giving high overhead, which we need to remove somehow..
    Last edited by sc7; 11-09-2018 at 06:33 PM.

  10. #10
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    The code looks correct to me, but I did warn you that it was unlikely to beat the time limit. Those kinds of problems can't usually be solved by a brute force approach. You need to find a "trick".

    Do you have any specific input for which the code in post#8 gives the wrong output?

    Anyway, I feel like I don't really understand the problem. k seems totally pointless. And the way I understand it, you could just keep track of where the two largest streaks of 1's are situated with respect to the current "first" element.
    Last edited by john.c; 11-09-2018 at 06:29 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  11. #11
    Registered User
    Join Date
    Nov 2018
    Posts
    32
    My bad, I ran the wrong file .. the code works fine, just can't beat the time limit.

    Do you have something in mind , about this "tricky" approach, I can't think of any, maybe a pattern or something like that ??

    track of two largest streaks ?? how ?? can you maybe show a code snippet of that or something? cause I don't know what you mean by that ...
    Last edited by sc7; 11-09-2018 at 06:53 PM.

  12. #12
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    Well, correct me if I'm wrong, but if in a 1500 bit sequence you knew that the two longest streaks of 1's were one beginning at position 100 going for 42 bits and another starting at position 1202 going for 37 bits, then what is the longest run of 1's if I move the start of the sequence to position 110? What about position 102?

    But if that trick actually worked, then it seems too simple, doesn't it? Can you post the link so I can read the original description myself?
    A little inaccuracy saves tons of explanation. - H.H. Munro

  13. #13
    Registered User
    Join Date
    Nov 2018
    Posts
    32
    here's the link to the problem : Contest Page | CodeChef

  14. #14
    Registered User
    Join Date
    Dec 2017
    Posts
    1,633
    I figured out why my trick won't work, and also what k is all about. You need to find the largest run of 1's <= k. So if the max is > k, you can't just return k. You need to return the run of 1's that's no greater than k, i.e., it could be less than k.

    Suppose you had run's of these lengths: 2, 5, 6, 7, 3.
    If k is 4, then the answer is 3 (not 4).

    So the counting routine (the slow one!) should be more like this:
    Code:
    int count_max_ones(vector<int> &nums, int first, int k) {
        int high = 0, cnt = 0;
        int i = first;
     
        do {
            if (nums[i])
                ++cnt;
            else {
                if (cnt <= k && cnt > high)
                    high = cnt;
                cnt = 0;
            }
            i = (i + 1) % nums.size();
        } while (i != first);
     
        if (cnt <= k && cnt > high)
            high = cnt;
     
        return high;
    }
    Last edited by john.c; 11-09-2018 at 07:05 PM.
    A little inaccuracy saves tons of explanation. - H.H. Munro

  15. #15
    Registered User
    Join Date
    Nov 2018
    Posts
    32
    No, please refer to the sample input and output on the page, It clearly tells with an explanation if your array is like [1,1,1,1,0] and k=3, then the largest subsequence, i.e, from i=0 till 3(containing 4 1's) will not be returned but, if we have 4 consecutive 1's then obviously we have 3 (=k) runs of 1 i,e i=0 till 2 so return 3.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. help w/optimization
    By dudeomanodude in forum C++ Programming
    Replies: 3
    Last Post: 02-08-2008, 02:45 PM
  2. optimization
    By strickey in forum C++ Programming
    Replies: 7
    Last Post: 04-19-2007, 05:28 AM
  3. Optimization.
    By Lithorien in forum C++ Programming
    Replies: 14
    Last Post: 10-07-2004, 12:21 AM
  4. optimization
    By krithi in forum C Programming
    Replies: 9
    Last Post: 01-19-2003, 10:52 AM
  5. IDE optimization
    By Traveller in forum A Brief History of Cprogramming.com
    Replies: 1
    Last Post: 07-04-2002, 02:01 AM

Tags for this Thread