Monday, July 29, 2013

SPOJ-1557::Can you answer these queries II

This is one of the difficult problems that i have solved. So i've decided to write an article about how to solve this problem.

Logically the problem statement is exactly like below.

Problem: Given a array of numbers a[1...n] (where duplicates are allowed), and a query range [x,y].
query(x,y) should return the sub-sequence sum, whose sum is maximum in the range [x,y] by satisfying uniqueness criteria.

Assume that a[x...y] is a sub-sequence having unique elements(i.e. with out duplicates).
Lets analyze the query asked for this range.
Query for range {x...y} can be expressed as below, assuming that all the queries {query(i,j) where j<y} were answered already.
query(x,y) =  max {
                 b(x,y),
                b(x+1,y),
                b(x+2,y),
                .
                ..
                ...
                b(y,y)
            }

where b(i,j) is defined as below.
b(i,j) = max {
            a[i],
            a[i]+a[i+1],
            a[i]+a[i+1]+a[i+2],
            ......
            a[i]+a[i+1]+a[i+2]+......+a[j]
        }

Lets go little further, do some sample calculations based on n values.
n-value possible Queries b-elements
1 query(1,1) b(1,1)
2
query(1,1),query(1,2)
query(2,2)
b(1,1),b(1,2)
b(2,2)
3
query(1,1),query(1,2),query(1,3)
query(2,2),query(2,3)
query(3,3)
b(1,1),b(1,2),b(1,3)
b(2,2),b(2,3)
b(3,3)

So you might have already observed the pattern that we are looking for.
Now Formal definitions of query(x,y) and b(i,j).
query(x,y) -> is the sub-sequence sum, whose sum is maximum in all sub-sequences by satisfying uniqueness criteria.
b(i,j)     -> is the maximum sub-sequence in the range[i...j] by satisfying uniqueness criteria.
Algorithm:
    Create an array/segment Tree as 'b'. (Segment tree is suggested, will explain that later)
    For i = 1 to N
        ->update the 'b' by inserting the element a[i].
        ->Answer all the queries query(x,y) where x<=y and y=i. 
How to handle repeativeness of the elements ??
 Assume that a[j] is the element to be inserted, 
           a[j] will make its contribution towards the elements b(i,j) {where i<=j}.
 Insertion operation is done based on the assumption that, 
           all the elements in the range a[i...j] will be unique.

 Lets assume that there is an element a[m] {where i <= m <= j} which is duplicate of a[j].
 By our theory, a[m] might have already made contribution towards the elements b(i,m) {where i<=m}.
 so elements b(k,j)  {where m+1 <= k <= j} can include a[j] which is unique for them now.

 In Other words, a[j] can make contribution to the elmements b(k,j) 
             {where m+1 <= k <= j and m-is the last know position of a[j].}
 i.e
 a[j] can be updated in the range b(last[a[i]]+1,j) which preserves our uniqueness condition.        

Complexity of the Query. ??
    To calculate each b(i,j), logN operations are required.(Worst case).
    To find max of b(i,j), for a query it will take y-x+1 no.of calulations under that element.

    ** b(i,j) is calculated based on below, so total j-i+1 child element calculations.
    {b(i+0,i+0), b(i+0,i+1), b(i+0,i+2).........b(i+0,j)
               b(i+1,i+1), b(i+1,i+2).........b(i+1,j)
                             b(i+1,i+2).........b(i+1,j)
                                      ...........
                                       b(j,j)}

    Total Complexity = O(N) = (j-i+1)O(logN) = O((j-i+1)*logN);
    worst case O(NlogN).
    *** Save the processing time by updating child elements by maintaining a segment Tree. 
        So the complexity will come down to O(logN)
How to maintain the Segment Tree Node.??
/*
    Suppose a[j] is to be updated.
    Please be aware that all the queries with y<j are already Calculated before hand.
    So update the tree only to maintain the queries where y==j.

    i.e. At a certain point of time, after updating a[j],
        Leaf Nodes: will contain info about the range queries required query(1,j),query(2,j),query(3,j).....query(j,j).
        Non-Leaf Nodes: will contain info about controling interval mentioned below them.

    So maintain 4-values at each node.
*/
    struct node{
        int max;  //-> Indicates maximum sum in the interval.
        int evermax;  //-> Indicates maximum sum the history of this range.
        int change;   //-> Indicates the value to be modified in the given range.
        int everchange; //-> Indicates the value to be modified in the history of this range.
    };
For example take the below input.
4
4 -2 3 -2
Inserting the A[4] = -2 in the sequence, the tree will look like.
                        (5,5,0,0)
        (5,5,0,0)                (3,3,-2,0)
(0,0,5,5)       (0,0,1,1)       (0,0,3,3)       (0,0,0,0)
Look at the Leaf nodes, these nodes will address these queries with y==4. May be you can name them as result nodes. :D
                        (5,5,0,0)
        (5,5,0,0)                (3,3,-2,0)
(0,0,5,5)       (0,0,1,1)       (0,0,3,3)       (0,0,0,0)
 q(1,4)          q(2,4)          q(3,4)          q(4,4)  
Look at the Non-Leaf nodes, they will have the control information(change,everchange), may be you can name them as control nodes. ;)
                        (5,5,0,0) -> control the interval (1,4)
        (5,5,0,0)              (3,3,-2,0)
   control the interval (1,2)      control the interval (3,4) -> -2 will be included in (3,4) range only
(0,0,5,5)       (0,0,1,1)       (0,0,3,3)       (0,0,0,0) 
Operations required:
You might have figured out that, after inserting a elment a[j] we are no longer looking at queries query(x,y) where y<j.
Hence we are updating the childrens with the current values as they are being updated.
so Operations required will be,
        updateChilds(node& left,node& right)//with the current insertion values(i.e changes required are propagated.)
        clearNode()                     // Clear the non-Leaf nodes.
        updateNode(node& left,node& right)  // Make control nodes are also capable of mataining the result information.
        setNode(int val)                 //Set result nodes to the respective values.

Following is my code,for which i have got AC after 20 attempts :P.
Be sure to look out for 'long long' ;)
// =====================================================================================
//       Filename:  _GSS2.cpp
//    Description:  
//        Created:  07/25/2013 08:42:25 PM
//         Author:  BrOkEN@!
// =====================================================================================
#include<fstream>
#include<iostream>
#include<sstream>
#include<bitset>
#include<deque>
#include<list>
#include<map>
#include<queue>
#include<set>
#include<stack>
#include<vector>
#include<algorithm>
#include<iterator>
#include<string>
#include<cassert>
#include<cctype>
#include<climits>
#include<cmath>
#include<cstddef>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>

#define TIMER 0
#define FOR(i,a,b) for(typeof((a)) i=(a); i <= (b) ; ++i)
#define FOREACH(it,x) for(typeof((x).begin()) it=(x).begin(); it != (x).end() ; ++it)
template< class T > inline T _max(const T a, const T b) { return (!(a < b) ? a : b); }


using namespace std;

const int MAX = 100001;
const int INF = 0x7f7f7f7f;
//const int INF = 0;

typedef pair<int,int> PI;
typedef vector<PI> VI;
typedef long long int __int;

typedef struct node
{
    __int max,evermax,change,everchange;
    
    node split(node& l, node& r){
    } // No Need of Split Function
    
    node updateChilds(node& l, node& r){
        l.everchange = _max(l.everchange,l.change+everchange);
        l.change += change;
        r.everchange = _max(r.everchange,r.change+everchange);
        r.change += change;
    }
    
    node setNode(int val){
        change += val;
        everchange = _max(change,everchange);
    }
    node clearNode(){
        change = 0;
        everchange = -INF;
    }
    node updateNode(node& l, node& r){
        max = _max(_max(l.max,l.evermax+l.everchange),_max(r.max,r.evermax+r.everchange));
        evermax = _max(l.evermax+l.change,r.evermax+r.change);
    }
    
} node;

typedef struct query{
    int l,r,p;
} query;

int a[MAX],lastp[MAX<<1],lastq[MAX];
__int ans[MAX];
node T[1<<18];
query q[MAX];


void update(int node, int i, int j, int a, int b, int val) {
    if(a <= i && j <= b) {
            T[node].setNode(val);
    }
    else {
        int m = (i + j)/2;
        T[node].updateChilds(T[2*node],T[2*node+1]);
        T[node].clearNode();
        if(a <= m) update(2*node, i, m, a, b, val);
        if(m < b) update(2*node+1, m+1, j, a, b, val);
        T[node].updateNode(T[2*node],T[2*node+1]);
    }
}

__int range_query(int node, int i, int j, int a, int b) {
    if(a <= i && j <= b){
        return _max(T[node].max,T[node].evermax + T[node].everchange);
    }
    else {
        int m = (i + j)/2;
        T[node].updateChilds(T[2*node],T[2*node+1]);
        T[node].clearNode();
        T[node].updateNode(T[2*node],T[2*node+1]);
        return _max((a <= m ? range_query(2*node, i, m, a, b) : -INF), 
                    (m < b ? range_query(2*node+1, m+1, j, a, b) : -INF));
    }
}

int main(){

    int N=0;    
    scanf("%d",&N);
    FOR(i,1,N){    
        scanf("%d", &a[i]);    
    }
    
    int M=0;    
    scanf("%d",&M);
    FOR(i,1,M){
            scanf("%d%d",&q[i].l,&q[i].r);
            q[i].p = lastq[q[i].r];
     lastq[q[i].r]=i;
    }

    FOR(i,1,N){
        update(1, 1, N, lastp[a[i]+100000] + 1, i, a[i]);
        lastp[a[i]+100000] = i;
        for(int j=lastq[i];j;j=q[j].p){
                ans[j]=range_query(1, 1, N, q[j].l, q[j].r);
        }
    }

    FOR(i,1,M){printf("%lld\n", ans[i]);}
    


    return 0;
}



Tuesday, May 28, 2013

[Algorithms] Binary Indexed Trees

Sources:
http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=binaryIndexedTrees
http://demonstrations.wolfram.com/BinaryIndexedTree/
http://www.algorithmist.com/index.php/Fenwick_tree

Basic Idea:
Given a set of 'n' Elements(Set F), then summarize set-F with a resulting data structure Tree(set T), with the equal number of elements as F.

For Each index in T , T[index] summarizes the information about the elements from 'index-2^r+1' to 'index' in F.

In other words, T[index] is responsible for elements F[index-2^r+1] .....F[index], where 'r' is the position of the last occurance of '1'.

Eg: See the below calculation to find out the range of each index[Max Value of index is 15 here].
Note: Neither set F is defined here nor T is derived here. This calculation is given to explain how ranges are considered at each Index of the Tree.

Table of Responsibility

 

Table of Responsibilty (Each index'ed element represents range [m,n]

 

 

Pictorial representation 

Define the Tree:
Now, since we know responsibility of ranges, set 'Tree' can be derived from a defined set 'F'.

Pictorial Representation 

How to Implement:
To implement the above idea, we need to follow the below procedures.
1. Find 'r' - i.e the last occurance of '1'.
2. Calulate the range[m,n] for each index based on r of that 'index'.
3. Represent set F as Cumulative frequencies.
4. Build the Tree based on the ranges given. T[index] = C[n]-C[m-1]; where [m,n] is the range covered by index.
5. Supporting required Operations on the implemeted Tree.
    a.Read the cumulative frequency.
    b.Read the actual frequency.
    c.Update the frequency and Update the tree
    d.Given a cumulative frequency, find the index. [This is not required As of now]
    e.UpScale/Downscale the entire frequencies in the Tree and update tree accordingly. etc.

Finding the Last Digit:
Okay, you are given a number 'N' and we need to find the position of last digit '1'.

representing N in binary format binary(N) = a1b   [where 'b' is sequence of 0's and 'a' is sequence of 1's&0's , B is Sequence of all 1's]
representing N'( N's Complement) in binary format binary(N') = (a1b)' +1 = a'1'b'+1 = a'0B +1 =  a'1b

N&N' = a1b & a'1b = (0..0)1(0..0) -> Last occurance of '1' is isolated.

Steps - 2,3,4 are easy to implement. At the end of step-4 , building of the BIT would be completed.

BIT should support necessary operations which are useful in range queries, otherwise its useless.
 

Reading the Cumulative Frequency:
For example, we want to read cumulative frequncy at index=13.

C[13]=C[1101] = Tree[1101] + Tree[1100] + Tree[1000] + T[0000]   = 3 + 11 + 12 + 0 = 26;
(i.e. Toggle the 1's from Right to left till the last; T[0000]=0 always coz we never use T[0], we leave that as it is in BITs;)

//psuedoCode:
int readCumulative(int idx){
int sum=0;
while(idx>0){
sum += Tree[idx];
idx -= (idx & -idx);
}
return sum;
}

Reading the Actual Frequency:
Simple approach: Actual frequency can be expressed as below.
    F[idx] =  C[idx]-C[idx-1];

//psuedoCode:
int readActual(int idx){
return readCumulative(idx) - readCumulative(idx-1);
}

But the complexity will be more(2*O(log maxVal)). So think of an optimal way.

C[13] = C[1101] = Tree[1101] + Tree[1100] + Tree[1000] + T[0000];
C[12] = C[1100] = Tree[1100] + Tree[1000] + T[0000];
Their Trees are matched after 12. So start with sum at idx=13 and substract the nodes till they match.

//psuedoCode:
int readActual(int idx){
int sum = Tree[idx];
if(idx>0){
int z = idx - (idx & -idx);
idx--;
while(idx!=z){
sum -= Tree[idx];
idx -=(idx & -idx);
}
}
}

Update the frequency and Update the tree:
If index 'idx''s frequency is updated , then all the Tree indexes which holds responsibility for this index are have to be updated.[Where ever the r of this idx is toggled.]

//psuedoCode:
void update(int idx,int val){
while(idx <=maxVal){
Tree[idx] += val;
idx += (idx & -idx);
}
}

UpScale/Downscale the entire Tree:upscale/downscale by factor c.

//psuedoCode:
void scale(int c){
for(int i=1;i<=maxVal;i++){
update(i, -(c-1)*readActual(i)/c);
}
}

//or Simple way is

void scale(int c){
for(int i=1;i<=maxVal;i++){
Tree[i] = Tree[i]/c;
}
}

[Algorithms] Segment Trees

Sources: TopCoder, LetUsKode, StackOverFlow and Google. 
http://community.topcoder.com/tc?module=Static&d1=tutorials&d2=lowestCommonAncestor
http://zobayer.blogspot.in/ 

Segment Trees mostly used for storing data and to provide easy access in range queries.

Basic Idea:

Each non-Leaf Node summarizes the information stored at descenedent leaves.
In Other words, Node 'i' will have summarized info about child Nodes at Kth Level.
    i.e. childs from i*2^k to (i+1)*s^k -1

Majorly two Operations are can be performed on a node in segTrees.
    Merge:     Summarize info stored at descendant nodes.
    Split:    Applying certain operations on descendant nodes.

And the following operations are done one the whole segTree.
    Initialize:    Initialize the segment tree.
    Update:     Update info of the leaf node and propagate the change till the root.
    Query:    Query function to be run over a Range or on a specific node(To check balanced state).

Generalized Code Template (In C++): [Node Structure and Operations done on a Node]

//
//Node Structure
struct node{
<type> <variable> ;

node merge(node& l, node& r){
//Apply your merge logic here.
}

node split(node& l, node& r){
//Apply Split logic here if you have any
}

node setValue(){
//Initialize variable in case of Leafnode creation or updation of a LeafNode
}

};

Generalized Code Template (In C++): [Operation that can be performed on segTree]

//
// initialization of Nodes
void init(int Node, int i, int j) {
if(i==j) { // Initialize Leaf Nodes
T[Node].setValue();
return;
}else{ // Summerize Descendant Nodes Nodes
int m = (i+j)/2;
init(2*Node, i, m);
init(2*Node+1, m+1, j);
T[Node].merge(T[2*Node],T[2*Node+1]);
}
}

//
// Update element with index 'idx' in the range [i,j]
void update(int Node, int i, int j,int idx, <values>) {
if(i==j && i == idx) { // Update the LeafNode idx
T[Node].setValue();
return;
}else{ // Summerize Descendant Nodes Nodes
int m = (i+j)/2;
if(idx <=m)
update(2*Node, i, m, idx, <values>);
else
update(2*Node+1, m+1, j, idx, <values>);
T[Node].merge(T[2*Node],T[2*Node+1]);
}
}

//
// Search for Node having interval info [L,R] in [i,j]; (i <= L < R <= r)
void range_query(node& resultNode,int Node,int i, int j, int L, int R){
if(i==L && j==R){
resultNode = T[Node];
return;
}else{
int m = (i+j)/2;
if( R <= m )
range_query(resultNode, 2*Node, i, m, L, R);
else if( L > m )
range_query(resultNode, 2*Node+1, m+1, j, L, R);
else{
node left,right;
range_query(left, 2*Node, i, m, L, m);
range_query(right, 2*Node+1, m+1, j, m+1, R);
resultNode.merge(left,right);
}
}
}

Practice Problems:
http://www.spoj.pl/problems/BRCKTS/  
http://www.spoj.com/problems/GSS3/
http://www.spoj.pl/problems/GSS1/       

Saturday, February 9, 2013

[Practice Mode] HackerCup-2013 Round-1 :: DeadPixel

Lession-11: General approach is always successful. For this problem,Just imagine how 'ROBO't Scans the book.
i.e. From left to right or top to bottom or right to left or bottom to top.
If you don't know yet, watch ROBO Movie :P ...Seriously.

Lession-12: Set is another beautiful STL Container that you need to know.

Lession-13: If you want to make use of sort at the best, I recommend not to use any comparator function. Believe it or not It runs out of memory if you use any comparator function.

Lession-14: Love C++ More and More, especially when there is no need to write Deque or Queue or Hashmap or Multimap or Set and other Standard function. Of course there are many languages which are having rich libraries but C++ has its own mark. May be my love towards pointers :P is coming out in dis way :D.

Lession-15: Jintak tak Jintak...Jinta...Jinta tha Thahhh...!! Working on Other problems.
// =====================================================================================
//       Filename:  deadPixel.cpp
//    Description:  
//        Created:  02/07/2013 04:06:57 PM
//         Author:  BrOkEN@!
// =====================================================================================

#include<iostream>
#include<sstream>
#include<fstream>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<iterator>
#include<queue>
#include<deque>
#include<stack>
#include<set>
#include<cstdio>
#include<cstdlib>
#include<cstddef>
#include<cstring>
#include<cctype>
#include<cmath>
#include<cassert>
#include<climits>
#include<ctime>

#define TIMER 1
#define MAX 40000

#define FOR(i,a,b) for(typeof(a) i=(a); i <= (b); i++) 
#define FOREACH(it,a) for(typeof(a.begin()) it=a.begin(); it != a.end(); ++it) 

using namespace std;

typedef pair<int,int> PI;
typedef vector<PI> VI;
typedef deque<PI> DQ;
typedef long long LL;

int W=0,H=0,P=0,Q=0,N=0,X=0,Y=0,a=0,b=0,c=0,d=0;
VI v;
DQ xs;


int getPossible(){
	set<int> k;
	FOREACH(i,xs){k.insert((*i).second);}
	k.insert(H);	
	
	int d=0,pre=-1;
	FOREACH(i,k){
		if((*i)-pre-1 >= Q){
			d+=((*i)-pre-1)-Q+1;
		};
		pre= *i;
	}

	return d;
	
}

LL solve(){
	v.clear();

	v.push_back(PI(X,Y));
	FOR(i,1,N-1){
		v.push_back(PI((v[i-1].first * a + v[i-1].second * b + 1) % W ,(v[i-1].first * c + v[i-1].second * d + 1) % H));	
	}	
	
	sort(v.begin(),v.end());

	LL sum=0LL;
	xs.clear();
	
	VI::iterator it=v.begin();
	FOR(d,0,W-P){
		while(!xs.empty() && ((xs.front()).first<d)){
			xs.pop_front();
		}

		while(it!=v.end() && (*it).first<=P-1+d){
			if(	(xs.empty()) || 
				((xs.back()).first<(*it).first) || 
				(((xs.back()).first==(*it).first) && ((xs.back()).second<(*it).second))
			){
				xs.push_back(*it);
			}
			++it;
		}
		sum+=(LL)getPossible();
	}
	return sum;
}

int main(){
#ifdef TIMER
	clock_t t=clock();
#endif
	int T=0;
	scanf("%d",&T);
	FOR(t,1,T){
		scanf("%d %d %d	%d %d %d %d %d %d %d %d",&W,&H,&P,&Q,&N,&X,&Y,&a,&b,&c,&d);
		printf("Case #%d: %lld\n",t,solve());
	}

#ifdef TIMER
	printf ("It took %f seconds to run.\n",((float)(clock()-t))/CLOCKS_PER_SEC);
#endif	
	return 0;
}

Wednesday, February 6, 2013

[Practice Mode] HackerCup-2013 Round-1 :: Security

Lession-7: Match finding is always an easy job, If you know HopCraft-Karp algorithm.

Lession-8: Lexicographic means Lexicographic, nothing else. You have a very small meta-dictionary Keep that in Mind. :P

Lession-9: Continue to read standard algorithms. :D

Lession-10: If you think that it can be fixed, It can be fixed.

// =====================================================================================
//       Filename:  security.cpp
//    Description:  
//        Created:  02/03/2013 01:22:50 AM
//         Author:  BrOkEN@!
// ====================================================================================

#include<iostream>
#include<sstream>
#include<fstream>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cstdio>
#include<cstdlib>
#include<cstddef>
#include<cstring>
#include<cctype>
#include<cmath>
#include<cassert>
#include<climits>
#include<ctime>

#define TIMER 1
#define NIL 0
#define INFINITE 1000
#define KMAX 101
#define MMAX 51
#define FOR(i,a,b) for(typeof(a) i=(a); i <= (b); i++) 
using namespace std;

typedef pair<int,int> PI;
typedef vector<PI> VI;
typedef set<VI> vS;

char k1[KMAX],k2[KMAX];
int m=0,l=0;
bool dp[MMAX][MMAX];
int H[2*MMAX][3];



bool compare(int a,int b){
 int x=l*a,y=l*b;
 for(int i=0;i<l;i++){
  if( (k1[x+i]!='?') && (k2[y+i]!='?') && (k1[x+i]!=k2[y+i])){
   return false;
  }
 }
 return true;
}


bool bfs(){
 queue<int> Q;
 FOR(v,1,m){
  if(H[v][1]==NIL){
   H[v][0]=0;
   Q.push(v);
  }else{
   H[v][0]=INFINITE;
  }
 }
 H[NIL][0]=INFINITE;
 while(!Q.empty()){
  int v=Q.front();Q.pop();
  if(H[v][0] < H[NIL][0]){
   FOR(u,1,m){
    if(v<=m && dp[v-1][u-1] && H[H[u+m][2]][0]==INFINITE){
     H[H[u+m][2]][0]=H[v][0]+1;
     Q.push(H[u+m][2]);
    }else if(v>m && dp[u-1][v%m -1] && H[H[u][2]][0]==INFINITE){
     H[H[u][2]][0]=H[v][0]+1;
     Q.push(H[u][2]);
    }
   }
  }
 }
 return (H[NIL][0]!=INFINITE);
}


bool dfs(int v){
 if(v!=NIL){
  FOR(u,1,m){
   if(v<=m && dp[v-1][u-1] && (H[H[u+m][2]][0]==H[v][0]+1) && dfs(H[u+m][2])){
    H[u+m][2]=v;
    H[v][1]=u+m;
    return true;
   }else if(v>m && dp[u-1][v%m -1] && (H[H[u][2]][0]==H[v][0]+1) && dfs(H[u][2])){
    H[u][2]=v;
    H[v][1]=u;
    return true;
   }
  }
  H[v][0]=INFINITE;
  return false;
 }
 return true;
}

bool hopCK(){
 FOR(i,0,2*m){H[i][0]=INFINITE;H[i][1]=NIL;H[i][2]=NIL;}
 
 int matching=0;
 
 while(bfs()){
  FOR(v,1,m){
   if((H[v][1]==NIL) && dfs(v)){ matching++; }
  }
 }

 return (matching==m); 
}

bool solve(){
 l=strlen(k1)/m;
 
 FOR(i,0,m-1){FOR(j,0,m-1){dp[i][j]=compare(i,j);}}

 if(!hopCK()){return false;} // Do you there won't be a matching exists, then just quit :P

 FOR(i,0,strlen(k1)){
  if(k1[i]=='?'){
   k1[i]='a';
   while(k1[i]<='f'){ 
    FOR(j,0,m-1){dp[i/l][j]=compare(i/l,j);}
    if(hopCK()){ break; }
    k1[i]++;
   }
   if(k1[i]=='g'){ return false; }
  }
 }
 
 return true;
}

int main(){
 clock_t t=clock(); 
 int T=0;
 scanf("%d",&T);
 FOR(t,1,T){
  scanf("%d\n%s\n%s",&m,k1,k2);
  if( solve())
   printf("Case #%d: %s\n",t,k1);
  else
   printf("Case #%d: IMPOSSIBLE\n",t);
 }
  
 t=clock()-t;
 printf ("It took me %ld clicks (%f seconds).\n",t,((float)t)/CLOCKS_PER_SEC); 
 return 0;
}

Tuesday, February 5, 2013

[Practice Mode] HackerCup-2013 Round-1 :: CardGame

Lession-1: Don't rush...Keep calm and settle down when you know the logic already.

Lession-2: 1,000,000,007 Is a Magic Number :P and Do Not IGNORE it.

Lession-3: Remember the Rule when working with Modulus Operation, "Apply mod before the result".
If you wait until the result to be computed, answers will be tossed away.
(a+b)mod m = (a mod m + b mod m) mod m;
(a*b)mod m = (a mod m * b mod m) mod m; 
Lession-4: Arrays are the Most beautiful data structure that you ever seen :D. Do not hesitate to use them to compute nCr and etc.

Lession-5: Every problem will have simple solution. Think smart not Bigger.

Lession-6: If you see a Modulus, be ready to solve it. Because modulo randomization always periodical. So Gear up.
// =====================================================================================
//       Filename:  cardGame.cpp
//    Description:  
//        Created:  02/02/2013 11:44:39 PM
//         Author:  BrOkEN@!
// =====================================================================================

#include<iostream>
#include<sstream>
#include<fstream>
#include<string>
#include<algorithm>
#include<vector>
#include<map>
#include<queue>
#include<stack>
#include<set>
#include<cstdio>
#include<cstdlib>
#include<cstddef>
#include<cstring>
#include<cctype>
#include<cmath>
#include<cassert>
#include<climits>
#include<ctime>


#define TIMER 1
#define NMAX 10001
#define MOD 1000000007L

#define FOR(i,a,b) for( typeof(a) i=(a); i < (b) ; ++i )

using namespace std;

int N=0,K=0;
long a[NMAX];
long nCr[NMAX][NMAX];


long solve(){
 sort(a,a+N);
 long sum=0L;K--;
 FOR(i,K,N){
  sum+=(a[i]%MOD * nCr[i][K]%MOD)%MOD;
 }
 return sum%MOD;
}

void preCompute(){
 FOR(i,0,NMAX){
  FOR(j,0,i+1){
   if(j==0) nCr[i][j]=1%MOD;
   else nCr[i][j]=(nCr[i-1][j-1]+nCr[i-1][j])%MOD;
  }
 }
}

int main(){
 clock_t t=clock();
 preCompute();
 int T=0;
 scanf("%d",&T);
 for(int t=1;t<=T;t++){
  scanf("%d %d",&N,&K);
  for(int i=0;i<N;i++){scanf("%ld",&a[i]);};
  printf("Case #%d: %ld\n",t,solve()); 
 } 
 t=clock()-t;
 printf ("It took me %ld clicks (%f seconds).\n",t,((float)t)/CLOCKS_PER_SEC); 
 return 0;
}

Tuesday, January 29, 2013

Facebook Hacker Cup 2013 Qualification Round(Solutions)

No intro is required.

you can find the qualification round problems in the below link.

https://www.facebook.com/hackercup/problems.php?round=185564241586420

Among the three problems, Problem1 and Problem2 are very easy if you come up with the logic soon.
And the third one is straight forward question with a very good logic.

Beautiful strings:
Like every one i started thinking very straight forward for this question, i.e. I need to process the sample data first to get the key string/algorithm as it is appears to be some kind of ciphering method is behind the scenes. 

ABbCcc with the answer 152, so i thought Ca(a)=24, Ca(b)=25 and Ca(c)=26.
So I was started thinking that its Caesar Cipher with shift 24.

So i continued to the second example. Kabooooommm...I was wrong :P

Still i was checking all the ciphering algorithms i knew substitution,transposition, rotational and Affine cipher etc etc.

Wait a minute, what if characters are assigned with values such that the Beauty(a.k.a. weight) of the string is maximized....it will become more beautiful right :P
#include<iostream>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<vector>
#include<string>
#include<list>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cassert>

using namespace std;

#define MAX 501

char str[MAX];

int findBeautyOfString(){
 int d[26]={0};
 int sum=0,i=0;
 while(str[i]!='\0'){
  if(isalpha(str[i])){d[tolower(str[i])-'a']++;}
  i++;
 } 
 sort(d,d+26);
 for(int i=1;i<=26;i++){sum+=i*d[i-1];} 

 return sum;
}


int main(){
 //ios_base::sync_with_stdio(false);

 int m=0;
 scanf("%d",&m);
 cin.getline(str,MAX);//tweak to skip first line

 for(int t=1;t<=m;t++){
  cin.getline(str,MAX); 
  printf("Case #%d: %d\n",t,findBeautyOfString());
 }

}
Balanced Smileys
Simple logic. Process the characters in forward direction and based on the result of the remaining string evaluate whether it is a balanced string or not.
Its like balanced parenthesis problem, but here we need to ensure that additional decisions have made proper if a smiley is observed.
#include<iostream>
#include<sstream>
#include<fstream>

#include<vector>
#include<string>
#include<list>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cassert>

using namespace std;

#define MAX 101

char str[MAX];
int n=0;

bool balanced(int index,int right){
 if(index==n){
  if(right>0){
   return false;
  }
  return true;
 }

 if(str[index]==')' && right==0)  return false;
 if(str[index]=='(')  return balanced(index+1,right+1);
 if(str[index]==')')  return balanced(index+1,right-1);
 if(str[index]==':' && index<n-1 && (str[index+1]==')'||str[index+1]=='(')){
   return balanced(index+2,right)|balanced(index+1,right);
 }
 return balanced(index+1,right);
}


int main(){
// ios_base::sync_with_stdio(false);
 
 int m=0;
 scanf("%d",&m);
 cin.getline(str,MAX);//Tweak to skip first line due to the usage of scanf to get m.

 for(int i=1;i<=m;i++){
  cin.getline(str,MAX);
  n=strlen(str);
  printf("Case #%d: %s\n",i,(balanced(0,0)?"YES":"NO"));
 }
}
Find the Min
This is the problem in which i felt ashamed for never trying to code python.
And I came to know about the power of python.
Logic is simple but the implementation is cumbersome for this problem considering the large data set range, which will make you to go mad to think.

For this one, i have first implemented with the use of hash map in cpp.
But i adopted a brute force method to find the n elements.
For small data set it was working but when it comes to large data set, memory allocation problems(Out of memory and glibc errors as i was coding in ubuntu) etc etc.
/*
Based on Hashmap
*/
#include<iostream>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<string>
#include<list>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cassert>

#define INS pair<int,int>

using namespace std;


map<int,int> m1,m2;
map<int,int>::iterator it1,it2;



int findNthNumber(int n,int k,int a,int b,int c,int r){
 m1.clear();
 m2.clear();
  
 printf("FindNumber: %d %d %d %d %d %d\n",n,k,a,b,c,r); 
 m2.insert(INS(-1,-1));
 m2.insert(INS(9999999,9999));
 m1.insert(INS(0,a));
 m2.insert(INS(a,0));
 it1=m1.begin();
 for(int i=1;i<k;i++){
  m1.insert(INS(i,(((b*(*it1).second)+c)%r)));
  ++it1;
  m2.insert(INS((*it1).second,(*it1).first));
 } 
   for(;it1!=m1.end();++it1){
    cout<<(*it1).first<<"\t"<<(*it1).second<<endl;
   }

 map<int,int>::iterator min,max,del1,del2,last;
 min=max=m2.begin();
 max++;
 int i=k;
 while(i<n){ 
  while((*min).first+1==(*max).first){
   last=m2.end();
   --last;
   if(max==last){
    min=max=m2.begin();
   }else{
    min=max;
   }
   ++max;
  }
  
  while((*min).first+1<(*max).first){
   
   
   m1.insert(INS(i,(*min).first+1));
   m2.insert(INS((*min).first+1,i));
   ++min;
   
   del1=m1.find(i-k);
   del2=m2.find((*del1).second);
   
   
   m1.erase(del1);
   if(del2==min){
    --min;
    m2.erase(del2);
    max=min;++max;
   }else if((*del2).first < (*min).first){
    min=del2;
    --min;
    m2.erase(del2);
    max=min;++max;
   }else if(del2==max){
    ++max;
    if(max==m2.end()){
     min=max=m2.begin();
     ++max;
    }
    m2.erase(del2);
   }else{
    m2.erase(del2);
   }
   
   if(i==n-1){
    last=m1.find(i);
    return ((*last).second);
   }
   i++;
  }
 }


 return 0;
}

int main(){
// ios_base::sync_with_stdio(false);
 
  
 
 int T=0;
 scanf("%d",&T);
 for(int t=1;t<=T;t++){
  int n=0,k=0,a=0,b=0,c=0,r=0;
  scanf("%d %d\n%d %d %d %d",&n,&k,&a,&b,&c,&r); 
  if(t==3) 
  printf("Case #%d: %d\n",t,findNthNumber(n,k,a,b,c,r)); 
 }
}
Later wrote the code in python, which was working fine but still the same result with large data set. But you know what , I liked python  and it is uber kewl :D.

A pattern was observed when i printed all the elements of the array in the end for a case, in the brute force method. Tada...!! there it is :D simplified. n I have google'd to find out more about "modulo randomization".

Start with 0, keep inserting the numbers if you don't find them last k. 

if you are deleting a front number which is less than the current number inserted you are free to insert that number just after the current number. 

Otherwise increase the number and continue with the procedure.

So on the whole next k+1 elements will have numbers from 0 to k(order will be different). But the same order will be repeated again for next k+1 elements also.
so you need to determine just k+1 elements from which you can make out the nth element.
/*
Based on Array
*/

#include<iostream>
#include<sstream>
#include<fstream>
#include<algorithm>
#include<iterator>
#include<vector>
#include<string>
#include<list>
#include<map>
#include<queue>
#include<deque>
#include<set>
#include<stack>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cassert>

#define __int64 unsigned long long int

#define KMAX 100001
#define MAX 200001


using namespace std;

__int64 n=0ULL,k=0ULL,a=0ULL,b=0ULL,c=0ULL,r=0ULL;
__int64 m[MAX]={0ULL};
int s[MAX]={0};

__int64 findNthNumber(){
 for(int i=0;i<MAX;i++){m[i]=0ULL;s[i]=0;} 

 __int64 sMax=k+k+1ULL;
 
 m[0]=a;
 if(m[0]<sMax) s[m[0]]++;
 for(__int64 i=1;i<k;i++){m[i]=(b * m[i-1] + c)%r;if(m[i]<sMax) s[m[i]]++;}
 
 __int64 i=0,j=k;
 
 while(j<sMax){
  while(s[i]==0){
   m[j]=i;
   s[i]++;
   if(m[j-k]<sMax){
    s[m[j-k]]--;
    if(m[j-k]<i && (s[m[j-k]]<=0)){ i=m[j-k]-1;}
   }
   i++;
   j++;
   if(j==sMax){break;}
  }
  i++;
 }
 
 return (m[k + (n - k - 1) % (k + 1)]);
}

int main(){
 int T=0;
 scanf("%d",&T);
 for(int t=1;t<=T;t++){
  scanf("%llu %llu\n%llu %llu %llu %llu",&n,&k,&a,&b,&c,&r); 
  printf("Case #%d: %llu\n",t,findNthNumber()); 
 }
}