I was trying to post this from the day SOPC2.0was conducted but I was short of Karma points. It was very ambiguous that all the solution getting highest score in question:-https://www.codechef.com/SOPC1602/problems/OPC1602 had exactly same code.Please look into the matter.
Cheating In SOPC2.0
Why do I get an NZEC?
Why m i getting NZEC (Non Zero Exit Code) for my program?
NZEC in Python
Doubt in SPOJ problem (Segmented tree)
This is the link to the problem problem
and this is my solution . Plz help me in finding the error
#include<stdio.h>
int arr[50003];
int sum[600000];
#define max(a,b) a>b?a:b
int main()
{
int n,j,m,l,r; scanf("%d",&n);
for(j=0;j<n;j++)
{
scanf("%d",&arr[j]);
}
scanf("%d",&m);
while(m--)
{
scanf("%d %d",&l,&r); l--; r--;
}
seg_tree(arr,0,n-1,0);
int c= query(0,n-1,l,r,0);
printf("%d\n",c);
return 0;
}
int seg_tree(int *arr,int l,int r,int i)
{
if(l==r)
{
sum[i]=arr[l];
return arr[l];
}
else
{
int mid=(l+r)/2;
sum[2*i+1]=seg_tree(arr,l,mid,2*i+1);
sum[2*i+2]=seg_tree(arr,mid+1,r,2*i+2);
if(sum[2*i+1]<0 && sum[2*i+2] <0)
{
sum[i]= max(sum[2*i+1],sum[2*i+2]);
return sum[i];
}
else if(sum[2*i+1]<0)
{
sum[i]= sum[2*i+2];
return sum[i] ;
}
else if(sum[2*i+2]<0)
{sum[i]= sum[2*i+1];
return sum[i] ;
}
else
{
sum[i]= sum[2*i+1]+sum[2*i+2];
return sum[i];
}
}
}
int query(int a,int b,int i,int j,int node)
{
if(a>j || b<i) return -16000;
else if(a>=i && b<=j)
return sum[node];
else
{
int mid=(a+b)/2;
int l=query(a,mid,i,j,2*node+1);
int r=query(mid+1,b,i,j,2*node+2);
if(l<0 && r <0)
{
return max(l,r);
}
else if(l<0)
{
return r;
}
else if(r<0)
{return l;
}
else
{
return (l+r);
}
}
}
SMPLSUM - Editorial
PROBLEM LINK:
Author:Kirill Shchetinin
Tester:Istvan Nagy
Editorialist:Xellos
DIFFICULTY:
EASY
PREREQUISITES:
Factorisation using the sieve of Erathostenes.
PROBLEM:
You're given many values of $N$; for each of them, compute $\sum_{K=1}^N \frac{N}{gcd(N,K)}$.
QUICK EXPLANATION:
Compute the first few terms by hand, find a simple formula in OEIS. Precompute the smallest prime divisors, use them to factorise $N$ and use that formula to compute the answer.
EXPLANATION:
The most efficient solution to our problem uses Google Search Algorithm. Just compute the first few values by hand and search for this sequence in OEIS. And look, it's here! There are two things to take from the page, which we'll call Result 1 and Result 2:
the answer is the sum of $d\cdot\varphi(d)$ for all divisors $d$ of $N$
the answer is the product of $\frac{p^{2e+1}+1}{p+1}=\frac{(p^e)^2\cdot p+1}{p+1}$ for all maximum prime powers $p^e$ dividing $N$
But it sucks to just state those results and provide a link to proofs - let's prove it all here as well!
Result 1 can be seen quite easily: the number of terms with $N/gcd(N,j)=d$ (each term must be a divisor of $N$, of course) is the Euler totient $\varphi(d)$. That's because we can rewrite this equality to $N/d=k=gcd(N,j)=gcd(kd,j)$, which can only hold if $j$ is a multiple of $k$ - that is, $j=lk$ for $0 < l \le d$. We can divide both sides by $k$ and get $1=gcd(d,l)$; the number of possible $l$-s coprime to $d$ and $\le d$ (which is the same as the number of $j$-s for which $N/d=gcd(N,j)$) is $\varphi(d)$.
In order to prove Result 2, we'll use Result 1. If $N=\prod_j p_j^{e_j}$ (the product goes over prime divisors of $N$), then any divisor $d$ can be written as $\prod_j p_j^{\alpha_j}$ for any $0 \le \alpha_j\le e_j$. The formula for $\varphi(d)$ is $\prod_j p_j^{\alpha_j-1}(p_j-1)$ for $\alpha_j > 0$; it can also be written as $\prod_j \varphi(p_j^{\alpha_j})$, where the factor for $\alpha_j=0$ is $\varphi(1)=1$.
Let's take some number $N > 1$ (for $N=1$, the answer is a product of nothing, which is 1). It'll be divisible by some prime $p$; let's cut out the max. power of this prime $p^e$ which divides $N$ and write $N=kp^e$. Then, we can take the sum over divisors to be the sum over exponents $\alpha$ of $p^\alpha$ and divisors of $k$:
$$\sum_{d|N} d\varphi(d)=\sum_{\alpha=0}^e \sum_{d|k} dp^\alpha \varphi(dp^\alpha)=\sum_{\alpha=0}^e \sum_{d|k} d\varphi(d) p^\alpha\varphi(p^\alpha) = \left(\sum_{\alpha=0}^e p^\alpha\varphi(p^\alpha)\right) \left(\sum_{d|k} d\varphi(d)\right)\,,$$
where the first sum is
$$\sum_{\alpha=0}^e p^\alpha\varphi(p^\alpha)=1+\sum_{\alpha=1}^e p^\alpha p^{\alpha-1}(p-1) = 1 + \sum_{\alpha=1}^e p^{2\alpha} - \sum_{\alpha=1}^e p^{2\alpha-1}=$$ $$ = \sum_{\alpha=0}^e p^{2\alpha} - \sum_{\alpha=0}^{e-1} p^{2\alpha+1} = \frac{p^{2(e+1)}-1}{p^2-1} - p\frac{p^{2e}-1}{p^2-1} = \frac{p^{2e+1}+1}{p+1}=p^{2e}-\frac{p^{2e}-1}{p+1}\,.$$
The second sum is just the answer for $N/p^e$ (note that $p^{2e+1}$ can overflow, for example if $N=p\approx10^7$). By continually cutting out primes this way, we eventually arrive at $N=1$ and obtain the factors of the answer as in Result 2.
It's not very hard to precompute divisors of all numbers up to $N=10^7$ (there are about $N\log N$ divisors of numbers up to $N$), then precompute all their totients $\varphi$ and simulate the sum over divisors, but with our limits, it's too slow. In fact, we can just barely manage to compute one prime divisor of each number using a modified sieve of Erathostenes - instead of just marking numbers as composite as in the original sieve, we're marking one prime for which they were found to be composite (or primes as their own prime divisors):
D[1..N] ={fill with zeroes} # one prime divisor of each number
for i in 2..N:
if D[i] == 0: # prime
# mark it as a divisor for all its multiples
for j in 1..N/i:
D[i*j] = i
This works in $O(N\log{N})$ time as well, but with a good constant factor.
With Result 2, however, all we need to do is decompose any $N$ into prime powers. With the precomputed primes, that's easy - as long as $N > 1$, we can just keep taking one prime divisor $p$ of $N$, divide $N$ by it as many times as possible and we've got $p^e$, with which we'll compute one factor of the answer. Since $N$ decreases quickly when we do this - we always divide it by at least $2$, so we'll reach $N=1$ in at most $O(\log{N})$ divisions - and computing the factors of our answer as per Result 2 is really fast, this is sufficient to solve the problem.
I'm not sure if I'd be able to make a fast enough solution using only Result 1. Sometimes, optimisation isn't a good idea...
ALTERNATIVE SOLUTION:
Could contain more or less short descriptions of possible other approaches.
AUTHOR'S AND TESTER'S SOLUTIONS:
The author's solution can be found here.
The tester's solution can be found here.
The editorialist's solution can be found here.
RELATED PROBLEMS:
Coding Calendar: android app for programmers
An useful app for keeping track of all coding contests happening across various websites like topcoder, codechef, hackerearth, etc.https://play.google.com/store/apps/details?id=com.limitskyapps.CodingCalendar
One can get notifications for new contests and can get reminders for the existing ones, if he/she chooses to. Hope you guys find it useful :-) I am one of the Developers.
Getting wrong answer for SPOJ MENU problem
Serious Bug in February Long challenge
There's a serious problem!! There's a bug in the challenge problem of FEB16. Anyone can view the solution of the challenge problem. My friend told me that even he can view my solution. He saw that some other user has also submitted the same code after after half an hour after I submitted the code. You can easily easy that his and mine code is same and I have submitted the code before. I use my own ubuntu terminal for coding.
@admin, Please look into the matter as soon as possible.
I just do not want to fall in the trap of plagiarism.
SEATR2 - Editorial
PROBLEM LINK
Panel Members
Problem Setter:Sergey Nagin
Problem Tester:Istvan Nagy
Editorialist:Sunny Aggarwal
Contest Admin:Praveen Dhinwa
Russian Translator:Sergey Nagin
Mandarin Translator:Hu Zecong
Vietnamese Translator: VNOI Team
Language Verifier: Rahul Arora
DIFFICULTY:
medium
PREREQUISITES:
Dynamic Programming, Number Theory, Trees
PROBLEM:
Given a rooted tree $T$ consisting of $N$ nodes and an integer $M$. We are asked to calculate the number of ways of putting integers from range $[1, M]$ in each node of the tree $T$ such that for any pair of nodes $\left(A, B\right)$ ( where $A$ is parent of node $B$ ) the number assigned to node $B$ is divisible by the number assigned to node $A$. Since this answer can be very large, Print the answer modulo $10^9 + 7.$
QUICK EXPLANATION
Number of valid configuration (as mentioned in problem statement) for a tree rooted at a node can be computed from the valid configuration of trees rooted at its children nodes i.e number of ways of assigning a particular number say $K$ to a node say $V$ such that the tree rooted at node $V$ has a valid configuration can be calculated from the number of ways of assigning multiples of number $K$ to the children nodes of $V$ such that trees rooted at children nodes also has a valid configuration.
EXPLANATION
Lets use some notation to make the explanation more understandable. Let us consider that the function $F_{\left(V, K\right)}$ denotes the number of ways of assigning a number $K$ to the node $V$ such that tree rooted at node $V$ has a valid configuration and the function $D_{\left(V, K\right)}$ denotes the number of ways of assigning any multiple of number $K$ to the node $V$ such that tree rooted at node $V$ has a valid configuration.
Therefore,
$$Required Answer = \bigg(\sum_{\substack{K \in [1, M]}}{F_{\left(1, K\right)}}\bigg) \% 10^9+7$$
How to compute $F_{(V, K)}$ for all $K \in [1, M]$ for any node $V$ ?
As mentioned above, number of ways of assigning a particular number say $K$ to a node say $V$ such that the tree rooted at node $V$ has a valid configuration can be calculated from the number of ways of assigning multiples of number $K$ to the children nodes of $V$ such that trees rooted at children nodes also has a valid configuration.
For any non leaf node $V$,
$$F_{\left(V, K\right)} = \prod_{\substack{U \in children(V)}}{D_{\left(U, K\right)}}$$
otherwise $$F_{\left(V, K\right)} = 1$$
Note that the function $F$ for a node $V$ depends upon the children nodes of $V$.
How to compute $D_{(V, K)}$ for all $K \in [1, M]$ for any node $V$ ?
Let us consider that we have already calculated $F_{(V, K)}$ for all $K \in [1, M]$.
Then, For some $K \in [1, M]$ $$D_{\left(V, K\right)} = \sum_{\substack{Z \in multiple(K)}}{F_{\left(V, Z\right)}}$$
Note that the function $D$ for a node $V$ depends upon the function $F$ for the same node $V$ and can be computed using following simple procedure.
int D[M+1]; int F[M+1]; for(int i=1; i<=M; i++) { int j = i; while( j<=M ) { // iterating over multiples of i D[i] += F[j]; j += i; } }
Look at the following C++ code for the better understanding of above explanation:
int N, M; int F[N+1][M+1]; int D[N+1][M+1]; void dfs(int u, int p = -1) { bool isleaf = true; for(int i=1; i<adj[u].size(); i++) { if( adj[u][i] != p ) { isleaf = false; dfs(adj[u][i], u); } } if( isleaf ) { // leaf node base case for(int i=1; i<=m; i++) { F[u][i] = 1; } } else { // computing function F as per our recurrence for(int j=1; j<=m; j++) { int v = 1; for(int i=0; i<adj[u].size(); i++) { if(adj[u][i] != p) { v = 1LL * v * D[adj[u][i]][j]; } } F[u][j] = v; } } // computing function D using function F. for(int i=1; i<=m; i++) { int j = i; while( j <= m ) { D[u][i] += F[u][j]; j += i; } } }
COMPLEXITY
$O(NM\log(M))$ per test case.
AUTHOR'S AND TESTER'S SOLUTIONS:
The author's solution can be found here.
The tester's solution can be found here.
The editorialist's solution can be found here.
SIMILAR PROBLEMS:
Codeforces Testing round 10 - D
SEAPAIR - Editorial
PROBLEM LINK
Panel Members
Problem Setter:Sergey Nagin
Problem Tester:Istvan Nagy
Editorialist:Sunny Aggarwal
Contest Admin:Praveen Dhinwa
Russian Translator:Sergey Nagin
Mandarin Translator:Hu Zecong
Vietnamese Translator: VNOI Team
Language Verifier: Rahul Arora
DIFFICULTY:
Easy-Medium
PREREQUISITES:
Mathematics, Sorting, Greedy.
PROBLEM:
Given an integer $A ( 0 <= A <= 10^{100} )$ and $N$ pairs of integers of the form $(X, A/X)$ where $X$ is an integer and $A/X$ denotes the integer division of $A$ by $X$. It is also given that in no more than $K$ such pairs the value of $A/X$ is calculated incorrectly. Find the number of possible values of $A$ modulo $10^9+7$.
QUICK EXPLANATION
For a given pair $(X, A/X)$, if value of $A/X$ is calculated correctly then the possible set of values that $A$ can take according to this $X$ can be represented as a range from $L$ to $R$ where $L = X * (A/X)$ and $R = X * (A/X) + X - 1$. We can represent all the given pairs as ranges $(L, R)$ and as it given that in no more than $K$ such pairs the value of $A/X$ is calculated incorrectly, answer will be the count of values that belongs to atleast $N-K$ ranges.
EXPLANATION
Let us represent $i^{th}$ pair of integer as range $L_i$ to $R_i$. Now, in order to calculate the number of integers that belongs to atleast $N-K$ ranges, represent a range as $2$ separate pairs $(L_i, 0)$ and $(R_i, 1)$ where $0$ denotes a marker for the starting of a range and $1$ denotes a marker for ending of a range. Sort all the $2*N$ pairs according to the first value.
Let us consider the following example to understand the solution better.
$N = 3, K = 1$
$(X_1, A/X_1) = (30, 2)$
$(X_2, A/X_2) = (40, 2)$
$(X_3, A/X_3) = (50, 2)$
Representing given pairs of integers as ranges:
$(L_1, R_1) = (30 * 2, 30 * 2 + 30 - 1) = (60, 89) = (60, 0)$ and $(89, 1)$ where $0$ denotes starting marker and $1$ denotes ending marker.
$(L_2, R_2) = (40 * 2, 40 * 2 + 40 - 1) = (80, 119) = (80, 0)$ and $(119, 1)$
$(L_3, R_3) = (50 * 2, 50 * 2 + 50 - 1) = (100, 149) = (100, 0)$ and $(149, 1)$
Sort the given ranges according to $1^{st}$ value.
$(60, 0), (80, 0), (89, 1), (100, 0), (119, 1), (149, 1)$
Now, maintain a counter to keep track for the number of ranges that an integer belongs to. Whenever a starting marker is encountered increment the counter variable by $1$
and decrement it by $1$ whenever an ending marker is encountered. Look at the below image to understand it better.
Now use this counter to calculate the count for the numbers that belongs to atleast N-K ranges. Look at the following fragment of code.
int mod = 1000000007; int counter = 0; // initialising counter to 0 int previous = 0; for(int i=0; i<2*N; i++) { if(A[i].second == 0) { counter ++; // incrementing counter on starting marker if( counter == N - K ) { previous = A[i].first; // value where we find our counter = N - K } } else { counter --; // decrementing counter on ending marker if( counter == N - K - 1 ) { // it means the value of counter upto this point // was at least N - K ans += A[i].first - previous + 1;
ans %= mod; } } }
NOTE: If $K$ = $N$ then all the given values of $A/X_i$ may be incorrect. In that case any value in the range $\in$ $[0, 10^{100}]$ can be a value for A. Therefore, the answer to such case is $(10^{100}+1) \% (10^9+7).$
Please refer tester's solution for better understanding of solution.
COMPLEXITY
$O(N\log(N))$
AUTHOR'S AND TESTER'S SOLUTIONS:
The author's solution can be found here.
The tester's solution can be found here.
The editorialist's solution can be found here.
SIMILAR PROBLEM
SEATR - Editorial
PROBLEM LINK
Panel Members
Problem Setter:Sergey Nagin
Problem Tester:Istvan Nagy
Editorialist:Sunny Aggarwal
Contest Admin:Praveen Dhinwa
Russian Translator:Sergey Nagin
Mandarin Translator:Hu Zecong
Vietnamese Translator: VNOI Team
Language Verifier: Rahul Arora
DIFFICULTY:
Hard
PREREQUISITES:
Dynamic Programming, Tree, Memoization, Mathematics.
PROBLEM:
A tree is an undirected graph on $N$ vertices with $N-1$ edges and no cycles. Let just consider a peculiar way of comparing two trees. To describe it, let's start with the way, we have stored a tree. For every tree $T$, we has a value $V$ — the root of the tree, and for every vertex $i$, we have an ordered list $Q_i$ with $L_i$ elements — $Q_{i, 1}, Q_{i, 2}, ..., Q_{i,L_i}$ which are children of the vertex $i$. We assume that the two trees will be equal if their roots are the same and for every $i$, the ordered list $Q_i$ is the same in both the trees.
Consider the given tree $T_1$ $[V=1, Q_1=[2, 3], Q_2=[], Q_3=[]]$ and $T_2$ given as $[V=1, Q_1=[3, 2], Q_2=[]$$, Q_3=[]]$, they will be considered different because $Q_1$ in the first tree is not equal to $Q_1$ in the second tree.
Let us consider that the $E_i$ denotes the number of vertices adjacent to vertex $i$. Given an array $C$ of $N$ elements, Let $f(C)$ be the number of different trees such that there exists a permutation $P_1, P_2, ... , P_N$ so that $E_{P_1} = C_1, $$E_{P_2}= C_2, ... , E_{P_N} = C_N$. We are provided with array $C$ and asked to compute the number $f(C)$ modulo 1000000007 $(10^9+7)$.
EXPLANATION
It is easy to notice that if $1$ permutation satisfies a configuration of the tree then every possible permutation will satisfy same configuration. So, we will first compute the number of different trees possible for a given permutation say 1, 2, 3, .... N and then will multiply this answer with N!.
Let us consider some notation to understand the solution better. Let us consider a function $F(A)$ denotes the number of different trees possible when there are exactly $A_i$ nodes in each tree with $i$ adjacent nodes. Let us consider another function $G(size, A)$ denotes the number of different tree possible when there are exactly $A_i$ nodes in each tree with $i$ adjacent nodes but each tree root has exactly $size$ number of adjacent nodes.
How to calculate $G(size, A)$ ?
$G(size, A)$ denotes the number of different trees possible (say $T$) when there are exactly $A_i$ nodes in each tree with $i$ adjacent nodes but each tree root ( say $R$) has exactly $size$ number of adjacent nodes. We can compute $G(size, A)$ by choosing a subset of $A$ (say $Z$) and can assign the chosen subset to the first child of root node $R$ and can distribute the remaining set of nodes over the remaining $size-1$ children of root node.
i.e
$$G(size, A) = \sum_{\substack{ Z \subset A }}{F(Z) * G(size-1, A-Z)}$$
How to calculate $F(A)$ ?
$F(A)$ is itself dependent on function. $F(A)$ can be calculated as follows:
i.e
$$F(A) = \sum_{ if (A_i \gt 0) }{G(i, X)}$$
where $X$ = updated $A$ with $X_i = A_i - 1$ as we have selected $1$ node with $i$ adjacent nodes as root.
NOTE: We have received linear time solutions for this problem during the contest. So, Please have a look on them. This is an overview of author's approach. I am still not very much clear with the idea so any suggestions and contributions to this post is welcome.
Please have a look at author's solution to learn more about the discussed solution.
COMPLEXITY
Exponential Time
AUTHOR'S AND TESTER'S SOLUTIONS:
The author's solution can be found here.
The tester's solution can be found here.
SIMILAR PROBLEM
ASP - Editorial
PROBLEM LINK:
Author:Jingbo Shang
Tester:Xiaoxu Guo
Editorialist:Pushkar Mishra
DIFFICULTY:
Simple
PREREQUISITES:
Ad-hoc
PROBLEM:
Given an array $A$, output "YES" if the array is sortable by moving the elements at maximum one index from their respective positions, otherwise output "NO".
EXPLANATION:
The given array is indexed from 1 to $N$. We maintain an auxiliary array $Mark$ which is initially set to 0.
Now, let us consider the first two elements of the array, i.e., $A[1]$ and $A[2]$. If $A[1] \leq A[2]$ then we needn't do anything. However, if $A[1] > A[2]$ then we need to swap $A[1]$ and $A[2]$. If we swap $A[1]$ and $A[2]$, we change $Mark[2]$ from $0$ to $1$. Doing so tells us that the element at position 2 wasn't at this position in the original array.
Next we consider elements at positions $A[2]$ and $A[3]$. If $Mark[2] = 1$, this would mean that the element at position 2 actually came from position 1. Since it has already been moved from its position, it can't be moved to the further right. This tells us that if $Mark[2] = 1$ and $A[2] > A[3]$, then the array can't be sorted according to the given rules. On the other hand, if $A[2] \leq A[3]$, then we simply go onto the next pair of elements, i.e., $A[3]$ and $A[4]$. If $Mark[2] = 0$ and $A[2] < A[3]$, then we swap $A[2]$ and $A[3]$, change $Mark[3]$ from $0$ to $1$ and again proceed to considering the next pair of elements, i.e., $A[3]$ and $A[4]$.
This gives us the first part of our algorithm:
func sortable(A) { Mark = {0};for (int i = 1 to N-1) { if (A[i] > A[i+1] and Mark[i] == 1) { return false; } else if (A[i] > A[i+1]) { Mark[i+1] = 1; } } /* MORE CODE TO BE ADDED. READ ON! */ return true;
}
The function isn't complete. It only checks whether the swaps made were valid are not. There is one more thing we need to check before we can return true. After all the swaps have been made and the function hasn't returned false, we need to check whether the array is actually sorted or not. Thus, the complete algorithm is as follows:
func sortable(A) { Mark = {0}; for (i = 1 to N-1) { if (A[i] > A[i+1] and Mark[i] == 1) return false; else if (A[i] > A[i+1]) Mark[i+1] = 1; } for (i = 1 to N-1) { if (A[i] > A[i+1]) return false; } return true; }
COMPLEXITY:
$\mathcal{O}(N)$ per test case.
SAMPLE SOLUTIONS:
STEM - Editorial
PROBLEM LINK:
Author:Jingbo Shang
Tester:Xiaoxu Guo
Editorialist:Pushkar Mishra
DIFFICULTY:
Easy
PREREQUISITES:
Strings, In-built data structures, Hashmaps
PROBLEM:
Given $N$ words, find the longest such word which is common to all of them.
EXPLANATION:
The first things to note are that the length of all the words is $\leq 20$ and there can be a maximum of 10 words. Let the longest word in the given set of words be of length $L$. Thus, the total number of distinct substrings we can get from this word is $\mathcal{O}(L^2)$. Accordingly, the total number of distinct substrings that we can get from the set of words is $\mathcal{O}(NL^2)$.
Once, we have a list of all the distinct substrings, we just need, for each word, the number of words which it appears in. If it appears in all the $N$ words, then it can be a potential candidate for our answer.
How do we implement this? We can use an in-built implementation of hashmap that is available in the language you are using. The hashmap will be organised as $ map< key,\, list> $. The $keys$ here are the distinct substrings from the given set of strings. For each $key$, we store a list of indices of words which it appears in. We can build this structure by taking one word at a time (say the $i^{th}$ word) examining each its substrings, and putting inserting $i$ in the list associated with the substrings in our map. The word can contain a same substring twice. For example, $anan$ contains $an$ twice. Thus, we have to make sure that we dont insert $i$ twice into the list of a substring which appears twice in it.
Here is the pseudocode:
func get_stem(words []) { for (i = 1 to N in words) { for (all substrings `subs' of words[i]) { if(map[subs].insert doesn't contain i) map[subs].insert(i); } }for(all keys `k' in the map) if(k = longest and lexicographically smallest word with associated list of size = N) return k;
}
COMPLEXITY:
$\mathcal{O}(NL^3\log (NL^2))$ per test case.
SAMPLE SOLUTIONS:
PP - Editorial
PROBLEM LINK:
Author:Jingbo Shang
Tester:Xiaoxu Guo
Editorialist:Pushkar Mishra
DIFFICULTY:
Medium-Hard
PREREQUISITES:
Strings, Tries, Rolling Hash, Palindromes
PROBLEM:
Given $N$ words, $S[1..N]$, output the number of ordered pairs $(i,\,j)$ such that $S[i]$ concatenated with $S[j]$ gives a palindrome.
EXPLANATION:
Let there be two words $x$ and $y$. Let us look at the cases that arise when they are concatenated (i.e., $x+y$) from the point of view of palindromes:
Case 1: $length(x) < length(y)$:
In this case, let us assume that $y'$ is that suffix of $y$ which is of the same length as $x$. If $x+y$ is to be a palindrome then two conditions must be true - $x = y'$ and $y-y'$ is a palindrome. For example, $aba$ and $ccaba$ will form a palindrome upon concatenation but $aba$ and $cdaba$ won't.Case 2: $length(x) > length(y)$:
In this case, let us assume that $x'$ is that prefix of $x$ which is of the same length as $y$. If $x+y$ is to be a palindrome then two conditions must be true - $y = x'$ and $x-x'$ is a palindrome.Case 3: $length(x) = length(y)$:
In this case, if $x+y$ is to be a palindrome then $x = y$.
These three cases lead us to formulate an algorithm. We need a data structure which can match prefixes of strings quickly. A trie is exactly for this purpose. We will take the words one by one, and put them in the trie. Before inserting word $i$, we will first find the number of words already in the trie that it forms a palindrome with upon being concatenated (word $i$ being the second part in concatenation), and then insert it.
For finding the required numbers, we need to store two variables per node of the trie: $uptill$ and $below$. The variable $uptill$ stores the number of words that have the exact same letters as the ones from the root of the trie to this node. The variable $below$ stores the number of those words $w$ that have a prefix $w\'$ which contains the exact same letters as the ones from the root of the trie to this node and $w-w\'$ is a palindrome.
Keeping these operations in mind, we can define our $insert(w)$ and $getanswer(w)$ functions. The $insert(w)$ function inserts the word $w$ into the trie and $getanswer(w)$ calculates the number of words already in the trie with which $w$ would form a palindrome upon being concatenated.
We first define how $getanswer(w)$ works. It first reverses $w$. Let's call the new string $revw$. Then it starts at the root of the trie and goes down as per the letters of $revw$. When it is at a node which is at depth $i$ from the root, it has already processed the first $i$ letters of $revw$, i.e., the prefix of length $i$. Let us call the processed prefix $revw'$. If $revw-revw'$ is a palindrome, then the word $w$ can form palindrome upon being contenated with the words ending at this particular node. Hence, if $revw-revw'$ is a palindrome, we add the value stored in $uptill$ variable of this node to the answer (this counts all possibilities under case 1). Once we reach the node which is the last letter of $revw$, we add the values stored in the $below$ and $uptill$ variables of this node to our answer. This counts possibilities under case 2 and case 3.
The $insert(w)$ works in a similar way. For this, we don't have to reverse the word. We start at the root and go down the edges as per the letters in $w$. When we are at a node at depth $i$ from the root, we have already processed the prefix $w'$ of length $i$. At this node, we add 1 to the value stored in $below$ variable if $w-w'$ is a palidrome. When we reach the node which is last letter of $w$, we add 1 to the $uptill$ variable of the node.
How can we efficiently check whether a prefix of a word is a palidrome or not? We can use 'rolling hash' to calculate for a given word $w$ of length $N$ an array $mark$ in $\mathcal{O}(N)$ where $mark[i] = 1$ if the prefix $w[0..i]$ is a palidrome and $0$ otherwise. Thus we can preprocess each string before inserting it or calculating the number of strings it forms palindromes with upon concatenation. Please see the author's/editorialist's solution for an example of rolling hash. You can read more about it from these links:
http://www.geeksforgeeks.org/online-algorithm-for-checking-palindrome-in-a-stream/
https://en.wikipedia.org/wiki/Rolling_hash
http://courses.csail.mit.edu/6.006/spring11/rec/rec06.pdf
http://www.infoarena.ro/blog/rolling-hash
COMPLEXITY:
$\mathcal{O}(N)$
SAMPLE SOLUTIONS:
SLIS - Editorial
PROBLEM LINK:
Author:Jingbo Shang
Tester:Xiaoxu Guo
Editorialist:Pushkar Mishra
DIFFICULTY:
Medium
PREREQUISITES:
Segment trees
PROBLEM:
There are many ways to solve the Longest Increasing Subsequence (LIS) problem. There is a DP approach, a Patience sorting approach, and a Segment tree approach. We will use the last one to formulate our algorithm.
Since, $A[i] \leq 10^9$, we will have to compress the numbers into a smaller range. Since, the length of the array is $\leq 10^5$, we can compress the numbers into the range $1..10^5$. Now, we need to find the number of second-longest LIS in this compressed array.
Let us look at how we find the LIS in the compressed array $B[1..N]$ using segment trees. We process the elements of the array from left to right. We keep a segment tree whose nodes store the maximum of all the lengths of increasing subsequences ending on an element in their respective ranges. When we are processing $B[i]$, we first find the maximum in the range $1..B[i]-1$ using the segment tree. Let's say this maximum is equal to $L$. We then update the leaf associated with the $i^{th}$ index to $L+1$. We update its parents as well to reflect the new maximum in the range $1..B[i]$. Once we have processed all the $N$ elements, the length of the longest increasing subsequence lies in the root of the segment tree.
How can we get the number of LISes? For this, we store two variables per node, $max$ and $nmax$. The variable $max$ stores the maximum of the lengths of increasing subsequences ending on an element in the range that the node covers. The variable $nmax$ stores the number of increasing subsequences which have the length $max$. Now, when we are processing $B[i]$, we update the leaf associated with it by putting $max = L+1$ and $nmax = prevnmax$, where $prevnmax$ is the number of increasing subsequences of length $L$ (which is maximal) in the range $1..B[i]-1$.
This gives us a way to calculate the number of LISes in an array. How do we find the number of second-LISes? Our previous algorithm gives us an idea. This time, we will store 2 more variables per node: $smax$ and $nsmax$. The variable $smax$ stores second-maximum of all the lengths of increasing subsequences ending on an element in their respective ranges. The variable $snmax$ stores the number of increasing subsequences which have the length $smax$.
Now, during update and query operations on the segment tree, when we our combining two nodes $x$ and $y$, we can have three cases.
Case 1: $x.max > y.max$
In this case, we will check whether $y.max$ is equal to $x.smax$ or not. If it is, we add $y.nmax$ to $x.nsmax$. We then return $x$ as the result of this combining operation.Case 2: $x.max < y.max$
This case is analogous to Case 1. We will check whether $x.max$ is equal to $y.smax$ or not. If it is, we add $x.nmax$ to $y.nsmax$. We then return $y$ as the result of this combining operation.Case 3: $x.max = y.max$
In this case, we add $y.nmax$ to $x.nmax$ and $y.nsmax$ to $x.nsmax$. We then return $x$ as the result of this combining operation.
Once all the elements have been processed, our final answer lies in the $nsmax$ variable of the root.
COMPLEXITY:
$\mathcal{O}(N\log N)$ per test case.
SAMPLE SOLUTIONS:
FSFSFS - Editorial
PROBLEM LINK:
Author:Jingbo Shang
Tester:Xiaoxu Guo
Editorialist:Pushkar Mishra
DIFFICULTY:
Medium-Hard
PREREQUISITES:
Primes, Bitmask DP
PROBLEM:
Given a number $N$, in how many ways can we drop certain numbers from $N!$ such that the resulting product is maximum-possible perfect square.
EXPLANATION:
We need to somehow reduce the problem to something simpler. Let us think of the most obvious reduction that we can do: think in terms of primes.
Let us look at some of the key ideas which will give us a hint about our required complexity:
- Only prime factors of numbers should be considered.
- Each number could be treated as a set of prime factors.
- There is no number that contains two or more prime factors more than $\sqrt{3000}$.
- For small prime factors (less than $\sqrt{3000}$, only 16 primes), we record whether we have covered them or not.
- For large prime factors (greater than $\sqrt{3000}$), we just want to select at most one number to cover it. This number is either the number itself or a multiple of it.
We can now think of doing a bitmask-dp on the 16 primes that we need to deal with. The Bitmask DP is explained with comments in this solution:
http://ideone.com/7quMsb
COMPLEXITY:
$\mathcal{O}(2^{16} * 3000)$ in the worst case.
SAMPLE SOLUTIONS:
FRGTNLNG - Editorial
PROBLEM LINK:
Author:Kanstantsin Sokal
Tester:Jingbo Shang
Editorialist:Lalit Kundu
DIFFICULTY:
Cakewalk
PREREQUISITES:
Basic Programming
PROBLEM:
You have acquired a dictionary of $N$ words of a forgotten language. Meanwhile, you also know $K$ phrases used in modern languages. For each of the words of the forgotten language, your task is to determine whether the word is still in use in any of these $K$ modern phrases or not. Each phrase has $L$ words given in input.
EXPLANATION:
================
First, you just need to store all the $N$ words of the forgotten language and all the phrases. For each each word, then, you can traverse over all phrases and check if its present in any one of them. You can also build a single array of all the words from all phrases and then check for each forgotten language word if its present in the array or not.
If you want it to more efficient you can store all phrase words in a set where insertion is $O(\text{log}(\text{size}))$ and checking if a string is present or not is also $O(\text{log}(\text{size}))$.
For implementation, you need to know basic programming concepts and syntax of a language of your choice. You should know about arrays, conditionals, loops, input/output to solve this problem.
First, we include implementations in three popular programming contest languages.
C++ code
#include <iostream>
#include <vector>
using namespace std;
int main() {
int T;
cin >> T;
for (int cas = 1; cas <= T; cas++) {
// we use 'cas' because 'case' is a keyword
int N, K, L;
// allocate more than necessary
// note that phrases[i] is a vector of strings.
vector < string > phrase[55];
//array of forgotten words
string forgotten[109];
cin >> N >> K;
for (int i = 0; i < N; i++) {
cin >> forgotten[i];
}
for (int i = 0; i < K; i++) {
cin >> L;
for (int j = 0; j < L; j++) {
string S;
cin >> S;
phrase[i].push_back(S);
}
}
for (int i = 0; i < N; i++){
string answer = "NO";
//traverse over all phrases
for(int j = 0; j < K; j++){
//traverse over phrase[j]
for(int k = 0; k < phrase[j].size(); k++){
if(phrase[j][k] == forgotten[i])
answer = "YES";
}
}
cout << answer << (i==N-1 ? "\n" : " ");
}
}
}
Java Code
Note that java.util.Scanner provides an easy way to tokenize and read the input. However, for problems with huge inputs and strict time limits, it is not recommended because it is slow. Instead, one should use BufferedReader, like so:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
public class Main {
static String[] data;
public static void main(String[] args) throws IOException {
BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
int testCases = Integer.parseInt(bufferedReader.readLine());
while (testCases-- > 0) {
//get N and K
int forgottenLanguageWordsCount, modernLanguagePhrasesCount;
data = bufferedReader.readLine().split(" ");
forgottenLanguageWordsCount = Integer.parseInt(data[0]);
modernLanguagePhrasesCount = Integer.parseInt(data[1]);
//build array
String[] forgottenWords = bufferedReader.readLine().split(" ");
//build a single list with all words from all phrases
List<String> modernWordsList = new ArrayList<>();
for (int i = 0; i < modernLanguagePhrasesCount; i++) {
data = bufferedReader.readLine().split(" ");
int totalWordsInPhrase = Integer.parseInt(data[0]);
//add to list
modernWordsList.addAll(Arrays.asList(data).subList(1, totalWordsInPhrase + 1));
}
//use .contains method to check if present in list or not
for (int i = 0; i < forgottenLanguageWordsCount; i++) {
if (modernWordsList.contains(forgottenWords[i])) {
System.out.print("YES");
} else {
System.out.print("NO");
}
System.out.print((i + 1 == forgottenLanguageWordsCount) ? "\n" : " ");
}
}
}
}
Python code
T = input()
for cas in xrange(1,T+1):
N, K = map(int, raw_input().strip().split())
forgotten = raw_input().split()
allWordsfromPhrases = []
for i in xrange(K):
allWordsfromPhrases += raw_input().split()
ans = ""
for i in xrange(N):
if forgotten[i] in allWordsfromPhrases: ans += "YES "
else: ans += "NO "
print ans
Python is ridiculously easy in this problem. Note that the python code has a bit of different flavor, specifically the for..else statement.
Suggestions
I will directly quote kevinsogo from one of his editorials.
Now that you've learned that many, many things can go wrong even for such a simple problem, how does one go about preventing it?
Well, for one, it is usually hard to write a completely correct code in the first try. Therefore one should always test the code before submitting it! For example, use the sample data. The sample data is provided for two reasons:
- To ensure that you are following the input/output format correctly, and
- To ensure that you at least get some small inputs correctly.
However, if you pass the sample input, it doesn't mean you'll pass the actual input! So it still lies upon the contestant to ensure that their program will pass whatever kind of test case the judge can give to it. So if the judge returns WA, try making some inputs yourself, until you find one where your program fails. Then start debugging from there. In other problems, it is sometimes useful to make random input generators.
Also, there is the occasional problem that tests how well you follow instructions and handle many tricky edge cases. In such problems, speed/minute optimizations are secondary to correctness, so things like readability/modularity more important, at the expense of efficiency. See the sample programs above as examples, which were written partly with readability in mind.
COMPLEXITY
================
If we implement a brute force solution, there are worst case $\text{MAXL} * \text{MAXK}$ words and for each forgotten word, we do a linear search. So total complexity is $\text{MAXL} * \text{MAXK} * \text{MAXN}$.
Using set, complexity can be reduced to $\text{MAXL} * \text{MAXK} + \text{MAXN} * \text{log}(\text{MAXL}*\text{MAXK})$.
AUTHOR'S, TESTER'S SOLUTIONS:
STACKS - Editorial
PROBLEM LINK:
Author:Kanstantsin Sokal
Tester:Jingbo Shang
Editorialist:Lalit Kundu
DIFFICULTY:
Simple
PREREQUISITES:
binary search, data structures
PROBLEM:
Mike likes to compose his disks in stacks, but there's one very important rule: The disks in a single stack must be ordered by their radiuses in a strictly increasing order such that the top-most disk will have the smallest radius.
Mike initiates an empty set of disk stacks. Mike processes the disks in the given order $A_1, A_2, ..., A_N$ using the following pattern:
- If there is at least one stack such that Mike can put the current disk on the top of the stack without making it invalid, then he chooses the stack with the smallest top disk radius strictly greater than the radius of the current disk, and puts the current disk on top of that stack.
- Otherwise, Mike makes a new stack containing only the current disk.
Your task is to output the set of the stack top disk radii after the algorithm is done in non-decreasing order.
QUICK EXPLANATION:
======================
We build our solution incrementally and at each step we maintain an sorted array $S$ storing the top radii of all the stacks present. Using binary search, we can find the correct stack for a new disk. After replacing the top radii of such a stack, array $S$ still remains sorted.
EXPLANATION:
================
We are going to build our solution incrementally. That is, at each step we'll store the stacks we already have formed and then find the correct position for a disk and put it there.
Now, from the example, given in the problem statement, it should be pretty clear that we need not store all the radii present in a stack. Since, we just need to output the top radii, and also where a new disk goes also depends on the top radii, we can just store the top radii of each of the stack currently formed.
Let's say we have an array $S_1, S_2, ..., S_k$ which currently stores the top radii of all stacks currently formed in sorted order. And now, we want to insert a new disk with radius $x$ into this structure. So, we need to find smallest $S_j$(i.e. smallest $j$, since $S$ is sorted) such that $S_j > x$. And we update $S_j = x$. We know that $S_{j-1} \le x$ and $S_{j+1} \gt x$, so array $S$ still remains sorted after the update. So, at each step we apply binary search to find such an index $j$ and update the value $x$. If there is no such index found, we just create a new entry at the end of the array.
A[N] = input
S[N]
current_size = 0
for i=0 to N-1:
// find the first idx in the sorted array S, such that S[idx] > a[i].
// this can be done using a simple binary search.
int idx = binarySearch(size, a[i]);
S[idx] = A[i]
if(idx==size) size++;
for i=0 to size-1:
print S[i]
//searches for first index idx such that S[idx] > val
int binarySearch(size, val):
int lo = 0, hi = size - 1;
int ans = size;
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (a[mid] > x) {
ans = mid;
hi = mid - 1;
}
else {
lo = mid + 1;
}
}
return ans;
}
You can also use built-in function $\text{upper\_bound}$ instead of binary search. Also, we can solve this problem using multiset. We just have to perform simulation. So, first, let's try to write our algorithm in pseudo code first and then we'll try to think about what kind of data structure do we need to implement that algorithm efficiently:
A[N] = input
Data Structure DS;
for i=0 to N-1:
x = Find in DS smallest number greater than A[i]
if no such number:
DS.insert(A[i])
else:
//we place A[i] on the stack with top radii x
DS.delete(x)
DS.insert(A[i])
print DS in sorted order
Now, we just need to think what kind of data structure DS is. It should efficiently insert values, delete values and for a given value find smallest number greater than value. If you know STL, set is such a data structure which keeps its elements sorted and can insert, delete, find operations in O(\text{log}(size))$. But, set doesn't keep duplicates, while we need to keep duplicates, so we use multiset. A multiset allows duplicate values.While deleting in a multiset, if you delete by value, all occurences of value are deleted. So, we should first find a value, which will return an iterator and then we'll delete by iterator.
A[N] = input
multiset <int> myset;
multiset <int>::iterator it;
for i=0 to N-1:
//here we first insert and then we find smallest number greater than A[i]
myset.insert(A[i])
it = myset.find(A[i])
//right now, it points to A[i]
//since multiset keeps elements ordered
//so, next element should be the element we are looking for
//also, sets have bidirectional iterators and can be incremented/decremented easily
it++;
//no such element present
if it == myset.end():
DS.insert(A[i])
else:
myset.erase(it)
//traverse over multiset to print values
//values inside multiset are already sorted
for(it=myset.begin(); it!=myset.end(); it++)
print (*it)
COMPLEXITY:
================
$O(N \text{log} N)$, since each operation on multiset takes $O(\text{log}N)$, or in case of binary search, it takes $O(\text{log}N)$ at each step.
PROBLEMS TO SOLVE:
================
Problems involving binary search:
STRSUB
ASHIGIFT
STETSKLX
Problems involving STL containers:
Running Median
ANUMLA
AUTHOR'S, TESTER'S SOLUTIONS:
REIGN2 - Editorial
PROBLEM LINK:
Author:Kanstantsin Sokal
Tester:Jingbo Shang
Editorialist:Lalit Kundu
DIFFICULTY:
Easy-Medium
PREREQUISITES:
dynamic programming, greedy
PROBLEM:
There are $N$ castles that can be conquered by George. He has decided to conquer exactly $K$ castles during the next $K$ days, an aim he plans to achieve by conquering one castle every day for the next $K$ days.
As reported by King George's spies, $A_i + (j - 1) * B_i$ enemy knights will be protecting the $i^{th}$ castle during the $j^{th}$ day. When attacking a castle, if the King sends as many knights as those defending it, it's sufficient to be conquer that castle. Another requirement is that one knight cannot be sent to conquer two different castles.
As you are the king's trusted advisor, you can choose a set of $K$ castles, that the king should conquer. After you provide a set of castles, George will choose the order in which he will conquer them. You can assume that George always chooses the order which minimizes the total number of knights used during all the conquests.
Your task is to find the maximum possible total number of knights that can be used during the campaign and reached by delegating a set of $K$ castles to conquer. Also, you are not sure about the value of $K$, so you should find the optimal answer for each $K = 1, 2, ... , N$.
QUICK EXPLANATION:
======================
First sort arrays $A$ and $B$ in decreasing order of $B$ while preserving the mutual connectedness of $A_i$ and $B_i$. After that, we define $f(i, j)$ as maximum number of knights required for king to conquer a subset of $j$ castles from first $i$ castles. We can easily define recurrence relation and base cases of this DP solution.
EXPLANATION:
================
First of all let's observe the strategy of king. He is given a set of $K$ castles and two arrays $A_1, A_2, ..., A_K$ and $B_1, B_2, ..., B_K$ are given. For conquering castle $i$ on day $j$ he has to send $A_i + (j - 1)*B_i$ knights. His aim is to decide such an ordering of conquering such that total number of knights required is minimised.
Now, he has to pay $A_i$ for each castle $i$ independent of which day he conqueres it on. So, the ordering depends only on $B_i$. If we think of a greedy approach we should first conquer those castles with highest $B_i$ since, as the day number increases $(j-1)*B_i$ will also increase. So, this is the the strategy of king: Conquer all $K$ castles in non-increasing order of $B_i$.
Now, moving onto solving the problem. Let's solve for a particular $K$. So, we have to choose $K$ castles out of $N$ such that using king's approach maximum number of knights are used. Now, a greedy approach which selects only of basis of $A_i$ or $B_i$ would be certainly wrong. We should, by now, be thinking on terms of dynamic programming.
Now, if you remember subset sum DP, we kept our states as $(i, j)$ denoting that we are solving for first $i$ elements and we need to form a sum $j$. If we try to think on similar terms here, we should keep our states as $(i, j)$ denoting that we are solving for first $i$ elements and we need to select $j$ castles to maximise knights required according to king's strategy. Now, we have to make a decision that either we select $i^{th}$ castle or not. If we select it, do we know what its going to contribute i.e. how many knights are going to be required? For that we should know on which day king will conquer this castle. Now, here is the interesting part: if we sort the initial arrays in decreasing order of $B_i$, then we'll be sure that according to king's strategy $i^{th}$ castle will be conquered on last day because all other castles that will be selected will have $B_j$ less than $B_i$.
So, we first sort arrays $A$ and $B$ in decreasing order of $B$ while preserving the mutual connectedness of $A_i$ and $B_i$. After that, we define $f(i, j)$ as maximum number of knights required for king to conquer a subset of $j$ castles from first $i$ castles.
Recurrences can be define easily as:
f(i, j) = max(
\\don't select i'th castle
f(i - 1, j)
\\select i'th castle, add the cost
f(i - 1, j - 1) + (A[i] + (j - 1)*B[i])
)
Realising base cases is very easy. So, we calculate $f(N-1, i)$ for all $i = 1, 2, ..., N$ and print them.
COMPLEXITY:
================
Since there are $N^2$ states and transition cost between states is constant time, total complexity is $O(N^2)$.
PROBLEMS TO SOLVE:
================
KGP14D
KGP14H
MCHEF
CARDLINE
AUTHOR'S, TESTER'S SOLUTIONS:
ACM amritapuri round 2015
ACM Chennai and Kolkata replay rounds for 2015 were held recently. When will the replay round for ACM Amritapuri be hosted?
Also, will codechef publish editorial for the problem for the Onsite mirror of Amritapuri contest which was hosted today?