nirwandogra's blog

By nirwandogra, 12 years ago, In English

This question is from amritapuri prelimnary for regional qualification...... Obviously the contest is over now..........

Given a sequence S of '0' and '1' of length N, a subsequence of S is obtained by omitting some elements of S without changing the order of the remaining elements of S.

Given a subarray of a sequence S starting from some position 'a' and ending at some position 'b' (1 <= a <= b <= N), both inclusive, denoted by S(a,b), you have report the length of longest non-decreasing subsequence of S(a,b). By non-decreasing, we mean that a '0' never appears after a '1' in the subsequence.

Input (STDIN): The first line contains T, the number of test cases. Then T test case follow, each test case being in the following format. The first line contains N, the length of sequence S. The next line contains a string of 0's and 1's of length exactly N. The next line contains Q, which means that you have to answer Q queries. The next Q lines contain a pair of integers a,b (1 <= a <= b <= N), meaning that you have to report the length of longest non decreasing subsequence of S(a,b). There is no blank line between test cases.

Output (STDOUT): Output Q lines per test case, which is the answer for each query. Do not print a blank line between test cases. Constraints:

1 <= T <= 10 1 <= N <= 100,000 1 <= Q <= 100,000 Sample Input:

1 13 0011101001110 6 1 13 4 13 1 9 6 9 3 3 6 10

Sample Output:

9 6 6 3 1 4

Plz tell me the algorithm..........

  • Vote: I like it
  • 0
  • Vote: I do not like it

| Write comment?
»
12 years ago, # |
  Vote: I like it 0 Vote: I do not like it

Can you give example or sample test ??

and what express the Q,T ?

»
12 years ago, # |
Rev. 3   Vote: I like it 0 Vote: I do not like it

sorry I'm too late , I come back after I become blue :)

it's interesting problem, let me explain my idea:

first thing let me define each "01" in text S as node, notice that the longest non-decreasing subsequence necessarily contains ONE node

let's select one of these nodes then notice that if you want to calculate length of longest non-decreasing subsequence that contain this node you do it by calculating (number of zeros on the left of this node + number of ones on the right of this node)

so let's search for all nodes in string S and donate node[i] is the index of the i'th node

and for each node you can calculate length of the longest non-decreasing subsequence that contain the node in O(1) time (considering whole string not only in range a,b)

i'll donate length[i] is the length of longest non-decreasing subsequence that contain the i'th node

now you have got the nodes with the length of each one

now when you answer a query just consider the nodes that being in the range

select the node that has the biggest length[i] this node is the node of longest non-decreasing subsequence in range (a,b) since all nodes will decrease its length[i] with the same number

note: to select the node that has the biggest length[i] effictively you need to use suitable data structer

this is my code (but I code it just to work with one test case you can easily edit it if you want):

#include <iostream>
#include <string>
using namespace std;
#define MAX 100005
int pre_ones[MAX];
int pre_zeros[MAX];
int n,k;
char str[MAX];
int nodes[MAX],t=0;
int RMQ[2*MAX][17]={0};
int p2[20];
int max(int a,int b){
	return (a>b)?a:b;
}
void RMQ_init(){
	for(int i=1;p2[i]<t;i++){
		for(int e=0;e<t;e++){
			RMQ[e][i]=max(RMQ[e][i-1],RMQ[e+p2[i-1]][i-1]);
		}
	}
	/*for(int i=0;p2[i]<t;i++){
		for(int e=0;e<t;e++){
			cout<<RMQ[e][i]<<" ";
		}
		cout<<endl;
	}*/
}
int RMQ_query(int a,int b){
	int len=b-a+1;
	int tmp=len;
	int ret=0;
	for(int i=0;p2[i]<=len;i++){
		if(tmp%2==1){
			ret=max(ret,RMQ[a][i]);
			a+=p2[i];
		}
		tmp/=2;
	}
	return ret;
}
int main(){
	p2[0]=1;
	for(int i=1;i<20;i++)p2[i]=p2[i-1]*2;
	int n;
	cin>>n;
	cin>>str;
	pre_ones[0]=0;
	pre_zeros[0]=0;
	for(int i=1;i<=n;i++){
		pre_ones[i]=pre_ones[i-1];
		pre_zeros[i]=pre_zeros[i-1];
		if(str[i-1]=='1'){
			pre_ones[i]++;
		} else {
			pre_zeros[i]++;
		}
	}
	for(int i=1;i<n;i++){
		if(str[i-1]=='0' && str[i]=='1'){
			nodes[t]=i;
			RMQ[t][0]=pre_zeros[i]+pre_ones[n]-pre_ones[i];
			t++;
		}
	}
	RMQ_init();
	int a,b,A,B,sol=-1;
	cin>>k;
	for(int g=0;g<k;g++){
		cin>>a>>b;
		int left=-1,right=t;
		while(right-left>1){
			if(nodes[(left+right)/2]<a){
				left=(left+right)/2;
			} else {
				right=(left+right)/2;
			}
		}
		A=right;
		left=0;
		right=t;
		while(right-left>1){
			if(nodes[(left+right)/2]<=b){
				left=(left+right)/2;
			} else {
				right=(left+right)/2;
			}
		}
		B=left;
		sol=0;
		if(A!=B){
			sol=max(sol,RMQ_query(A,B)-pre_zeros[a-1]-pre_ones[n]+pre_ones[b]);
		}
		sol=max(sol,pre_zeros[b]-pre_zeros[a-1]);
		sol=max(sol,pre_ones[b]-pre_ones[a-1]);
		cout<<sol<<endl;
	}
}

UPD: commenting some debug lines

»
12 years ago, # |
  Vote: I like it 0 Vote: I do not like it

i think this should work. correct me if i am wrong..

#include<iostream>
using namespace std;
typedef long long LL;


int main()
{
    int N;
    cin>>N;
    string input;
    cin>>input;
    int count=0;
    int count2=0;
    int zero[N],one[N];
    for(int i=0;i<input.size();i++)
    {
		if(input[i]=='0')
		{
			zero[i]=++count;
		}
		else
		{
			zero[i]=count;
		}
		if(input[i]=='1')
		{
			one[i]=++count2;
		}
		else
		   one[i]=count2;
	}
	int curr=-1;
	int right[N];
	for(int i=N-1;i>=0;i--)
	{
		if(input[i]=='1')
		{
			curr=i;
			continue;
		}
		
	    right[i]=curr;
	}
	 curr=-1;
	 int left[N];
	  curr=-1;
	for(int i=0;i<N;i++)
	{
		if(input[i]=='0')
		{
			curr=i;
			continue;
		}
		left[i]=curr;
	}
	
	cout<<endl;
	int q,a,b;
	cin>>q;
	while(q--){
	cin>>a>>b;
	a--;
	b--;
	int ans=max(zero[b]-(a-1>=0?zero[a-1]:0),one[b]-(a-1>=0?one[a-1]:0));
	if(input[a]=='0'&&right[a]!=-1)
	{
	   ans=	max(ans,right[a]-a+one[b]-(a-1>=0?one[a-1]:0));
	}
	if(input[b]=='1'&&left[b]!=-1)
	{
		
		int temp=(zero[b]-(a-1>=0?zero[a-1]:0))+(b-left[b]);
		
		ans=max(ans,temp);
	}
	
   cout<<ans<<endl;
}
		

  return 0;
}