Contest Solutions
Contest Solutions
Problem A:
Tutorial:
Let’s keep an array a of booleans, ai denoting whether or not some team has solved
the ith problem already. Now we can iterate through the string from left to right and
keep a running total tot. If ai is true (the i-th problem has already been solved), increase
tot by 1 ; otherwise, increase tot by 2 and set ai to true.
The time complexity is O(n).
Bonus: the answer is always n+number of distinct characters in s. Can you see why?
Solution:
#include <b i t s / s t d c ++.h>
using namespace s t d ;
void s o l v e ( ) {
int n ;
c i n >> n ;
string s ;
c i n >> s ;
bool v i s [ 2 6 ] = { } ;
int r e s = 0 ;
for ( char c : s ) {
i f ( ! v i s [ c − ’A ’ ] ) { r e s += 2 ; v i s [ c − ’A ’ ] = true ; }
e l s e { r e s ++;}
}
c o u t << r e s << ’ \n ’ ;
}
int main ( ) {
int t t ;
c i n >> t t ;
for ( int i = 1 ; i <= t t ; i ++) { s o l v e ( ) ; }
}
1
Problem B:
Tutorial:
You need to implement what is written in the statement. To quickly check if a word is
written by another guy, you should store some map < string, int > or Python dictionary,
and increment every time you see a new string in the input. Then, you should iterate
through each guy, find the number of times their word appears, and update their score.
The complexity is O(n · log(n)) per testcase. Solution:
#include <b i t s / s t d c ++.h>
using namespace s t d ;
void s o l v e ( ) {
int n ;
c i n >> n ;
map<s t r i n g , int> mp;
string a [ 3 ] [ n ] ;
for ( int i = 0 ; i < 3 ; i ++) {
for ( int j = 0 ; j < n ; j ++) {
c i n >> a [ i ] [ j ] ;
mp[ a [ i ] [ j ]]++;
}
}
for ( int i = 0 ; i < 3 ; i ++) {
int t o t = 0 ;
for ( int j = 0 ; j < n ; j ++) {
i f (mp[ a [ i ] [ j ] ] == 1 ) { t o t += 3 ; }
e l s e i f (mp[ a [ i ] [ j ] ] == 2 ) { t o t ++;}
}
cout << t o t << ’ ’ ;
}
c o u t << ’ \n ’ ;
}
int main ( ) {
ios : : sync with stdio ( false ) ;
cin . t i e ( nullptr ) ;
int t t ;
c i n >> t t ;
for ( int i = 1 ; i <= t t ; i ++) { s o l v e ( ) ; }
}
2
Problem C:
Tutorial:
We need to check whether if each cell is either visited by either X or Y. We just need
to make a table of bools with size n initially set to false and each time we read an integer
i visited by one of the players we change the status of the position i in the table to true
and after looping over all indices that are winnable by each players we iterate over the
visited table and if there is a single index not visited it’s not possible for them to pass
all levels, otherwise it’s possible.
The complexity of the solution is O(n)
Solution:
#include <b i t s / s t d c ++.h>
using namespace s t d ;
bool v i s [ 1 0 1 ] ;
int main ( ) {
int n , p , q ;
c i n >>n ;
c i n >>p ;
for ( int i =1; i<=p ; i ++){
int x ;
c i n >>x ;
v i s [ x]= true ;
}
c i n >>q ;
for ( int i =1; i<=q ; i ++){
int x ;
c i n >>x ;
v i s [ x]= true ;
}
bool ans=true ;
for ( int i =1; i<=n ; i ++){
i f ( ! v i s [ i ] ) ans=f a l s e ; // ans=ans&&v i s [ i ] ;
i f ( ! ans ) break ;
}
i f ( ans ) cout<<” I become th e guy . ” ;
e l s e cout<<”Oh, my keyboard ! ” ;
return 0 ;
}
3
Problem D:
Tutorial:
We can iterate through the array a and keep track of the length of the current blank
space. Whenever we encounter a 0, we increase the length of the current blank space,
and whenever we encounter a 1, we check if the current blank space is longer than the
previous longest blank space. If it is, we update the length of the longest blank space.
Finally, we return the length of the longest blank space.
The time complexity of this algorithm is O(n).
Solution:
#include <b i t s / s t d c ++.h>
using namespace s t d ;
void s o l v e ( )
{
int n ;
c i n >> n ;
int a [ n ] ;
int c nt = 0 , ans = 0 ;
for ( int i = 0 ; i < n ; i ++)
{
c i n >> a [ i ] ;
i f ( a [ i ] == 0 )
{
c nt++;
}
else
{
ans = max( ans , c nt ) ;
c nt = 0 ;
}
}
c o u t << max( ans , c nt ) << e n d l ;
}
int main ( ) {
int t = 1 ;
c i n >> t ;
while ( t −−) {
solve ( ) ;
}
}
4
Problem E:
Tutorial: We can keep track of our current point (x,y) as we iterate over the string:
• if si = L, then decrement x (x := x − 1);
• if si = R, then increment x (x := x + 1);
• if si = U , then increment y (y := y + 1);
• if si = D, then decrement y (y := y − 1)
Initially, set x = y = 0. If x = y = 1 is ever true, then we should output YES; otherwise,
we output NO.
The time complexity is O(n).
Solution:
#include <b i t s / s t d c ++.h>
using namespace s t d ;
void s o l v e ( ) {
int n ;
c i n >> n ;
string s ;
c i n >> s ;
int x = 0 , y = 0 ;
for ( int i = 0 ; i < n ; i ++) {
i f ( s [ i ] == ’L ’ ) {x−−;}
i f ( s [ i ] == ’R ’ ) {x++;}
i f ( s [ i ] == ’D ’ ) {y−−;}
i f ( s [ i ] == ’U ’ ) {y++;}
i f ( x == 1 && y == 1 ) { cout << ”YES\n” ; return ; }
}
c o u t << ”NO\n” ;
}
int main ( ) {
ios : : sync with stdio ( false ) ;
cin . t i e ( nullptr ) ;
int t t ;
c i n >> t t ;
for ( int i = 1 ; i <= t t ; i ++) { s o l v e ( ) ; }
}
5
Problem F:
Tutorial:
We will perform each move in reverse from the final sequence of the cypher.
• down move: it increases the i-th digit by 1. After applying the up move on 9, it
becomes 0.
• up move (denoted by D): it decreases the i-th digit by 1. After applying the down
move on 0, it becomes 9.
Now
Pn we just need to implement the two types of moves. The time complexity is O(n +
i=1 ai ) per test case.
Solution:
#include <b i t s / s t d c ++.h>
using namespace s t d ;
void s o l v e ( )
{
int n ;
c i n >> n ;
int a [ n ] ;
for ( int i = 0 ; i < n ; i ++)
{
c i n >> a [ i ] ;
}
for ( int i = 0 ; i < n ; i ++){
int b ;
c i n >> b ;
i f ( b == 0 )
{
continue ;
}
s t r i n g now ;
c i n >> now ;
for ( int j = 0 ; j < b ; j ++){
i f ( now [ j ] == ’U ’ ){ a [ i ]−−;}
e l s e i f ( now [ j ] == ’D ’ ){ a [ i ]++;}
i f ( a [ i ] < 0){ a [ i ]+=10;}
i f ( a [ i ] > 9){ a [ i ] −=10;}
}
}
for ( int i = 0 ; i < n ; i ++){
cout << a [ i ] << ” ” ;
}
c o u t << e n d l ;
}
int main ( ) {
int t ;
c i n >> t ;
while ( t −−){ s o l v e ( ) ; }
return 0 ;
}
6
Problem G:
Tutorial:
We just need to keep track of the first element that appears twice(let’s call it x) in the
interval [0, m − 1]. let i1 is the index of the first occurrence of x in the described sequence
and i2 is the second one, the answer is i2 − i1 .
The complexity of the solution is O(m)
Solution:
#include <i o s t r e a m >
using namespace s t d ;
int o c c [ 1 0 0 0 0 1 ] ;
int main ( ) {
int a , b , x , m, c = 0 ;
c i n >> a >> b >> m >> x ;
while ( ! oc c [ x ] ) {
o cc [ x ] = c ;
c++;
x = ( a ∗ x + b ) % m;
}
c o u t << c − o cc [ x ] << e n d l ;
}
7
Problem H:
Tutorial:
Sort sequence v to obtain sequence u. Sorting can be done in O(n · log(n)) using
quicksort. Now we are interested in the sum of a interval of a given sequence. This
can bePdone by calculating the prefix sum of the sequence beforehand. That is, let
svi = ij=1 vj . The sum of numbers in the interval [l, r] would then be svr − svl−1 . We
can deal with sequence u likewise.
Preprocessing takes O(n) time, and answering a query is only O(1). The total com-
plexity would be O(n · log(n) + q).
Solution:
#include<b i t s / s t d c ++.h>
using namespace s t d ;
long long i , k , l ,m, n , r , u [ 1 0 0 0 0 5 ] , v [ 1 0 0 0 0 5 ] ;
main ( )
{
c i n >>n ;
for ( i =1; i<=n ; i ++){
c i n >>u [ i ] ;
v [ i ]=u [ i ] ;
}
s o r t ( u , u+n +1);
for ( i =1; i<=n ; i ++)u [ i ]+=u [ i −1] , v [ i ]+=v [ i − 1 ] ;
c i n >>m;
while (m−−){
c i n >>k>>l >>r ;
i f ( k==1)cout<<v [ r ]−v [ l −1]<<e n d l ;
e l s e cout<<u [ r ]−u [ l −1]<<e n d l ;
}
}
8
Problem I:
Tutorial:
At first, let’s jump with +k while
P x is still greater than the current position. Now we
finished in some position pos = steps
i=1 i ≥ x. Note that 0 ≤ pos − x < steps; otherwise,
we wouldn’t make the last step. If pos = x, then we are lucky to finish right at point x.
Otherwise, let’s look at what happens if we replace one +k with −1. Basically, we’ll finish
in pos′ = pos − (k + 1). And since k ∈ [1, steps], then pos′ ∈ [pos − steps − 1, pos − 2].
We know that pos − step < x so if x < pos − 1 then we can choose the corresponding
k = pos−x−1 and replace +k with −1 and get straight to the point x. But if x+1 = pos
then we need √ one extra operation −1. To calculate steps fast we can note we need at
least steps = 2 · x − 1 since steps · (steps + 1) ≤ (steps + 1)2 ≤ 2x and then we can
increase steps while steps(steps + 1) < 2x.
Solution:
#include<b i t s / s t d c ++.h>
using namespace s t d ;
int main ( ) {
int t ;
c i n >> t ;
while ( t −−) {
int x ; c i n >> x ;
int s t e p s = 0 ;
while ( s t e p s ∗ ( s t e p s + 1 ) < 2 ∗ x )
s t e p s ++;
i f ( s t e p s ∗ ( s t e p s + 1 ) / 2 == x + 1 )
s t e p s ++;
cout << s t e p s << e n d l ;
}
}
9
Problem J:
Tutorial:
Consider deleting characters with numbers i and i + 1, as well as characters with
numbers i + 1 and i + 2. In the first case, the symbol with the number i + 2 remains, in
the second −i. Symbols with numbers less than i or more than i + 2 remain in both cases.
Therefore, the same strings will be obtained if the characters with the numbers i and i+2
match. Therefore, we just need to count the number of i such that : 1 ≤ i ≤ n − 2 and
si = si+2 , and subtract this value from n − 1.
The complexity of the solution is O(n)
Solution:
#include <i o s t r e a m >
using namespace s t d ;
void s o l v e ( ) {
int n ;
c i n >> n ;
string s ;
c i n >> s ;
int r e s = n − 1 ;
for ( int i = 1 ; i + 1 < n ; ++i ) {
i f ( s [ i − 1 ] == s [ i + 1 ] ) {
r e s −−;
}
}
c o u t << r e s << ’ \n ’ ;
}
int main ( ) {
int t ;
c i n >> t ;
for ( int i = 0 ; i < t ; ++i ) {
solve ( ) ;
}
}
10
Problem K:
Tutorial:
The problem can be written in the following way: for each index i denote ri as the
largest index such that ai + . . . + ari ≤ t. The problem is to find max(ri − i + 1).
One can see that ri are non-decreasing, so the problem can be solved with two pointers:
iterate over i and keep a pointer to corresponding ri .
Solution:
#include <b i t s / s t d c ++.h>
using namespace s t d ;
int main ( ) {
int n , t ;
c i n >> n >> t ;
v e c t o r <int> a ( n ) ;
for ( int& k : a )
c i n >> k ;
int r = 0;
int sm = 0 ;
int ans = 0 ;
for ( int i = 0 ; i < n ; ++i ) {
while ( r < n && sm + a [ r ] <= t ) {
sm += a [ r ] ;
++r ;
}
ans = max( ans , r − i ) ;
sm −= a [ i ] ;
}
return 0 ;
}
11
Problem L:
Tutorial:
For the current given constraint you can precalculate whether it is possible to obtain
each n for some k. To do this, we can iterate through all possible 2 ≤ k ≤ 106 and for
each of them calculate the values 1 + k + k 2 , 1 + k + k 2 + k 3 , ..., 1 + k + k 2 + k 3 + ... + k p ,
where p is such that 1 ≤ 1 + k + k 2 + k 3 + ... + k p ≤ 106 . For this version of problem it
is enougth to calculete valuse for p ≤ 20.
Note that the minimum number of snowflake layers is 3. Therefore, the calculations start
from the value 1 + k + k 2 .
We can store all the obtained values, for example, in a set. Alternatively, we can use an
array called ”used” and set the value 1 in the array element with the corresponding index
for each obtained value.
It is better to perform this precalculation before iterating through the test cases.
Then, for each test, we only need to read the value of n and check if we have obtained it
in the precalculation described above. √
The time complexity of the solution using a set is O( n · p · log(n) √ + tc · log(n)).
The time complexity of the solution using the ”used” array is O( n · p + tc).
Here tc - number of test cases.
Solution:
#include<b i t s / s t d c ++.h>
using namespace s t d ;
using LL = long long ;
s e t <long long> nums ;
int main ( ) {
for ( long long k = 2 ; k <= 1 0 0 0 ; ++k ) {
long long v a l = 1 + k ;
long long p = k∗k ;
for ( int c nt = 2 ; c n t <= 2 0 ; ++cn t ) {
v a l += p ;
i f ( v a l > 1 e6 ) break ;
nums . i n s e r t ( v a l ) ;
p ∗= k ;
}
}
int = 0, = 1;
c i n >> ;
for ( int = 0; < ; ++ ) {
long long n ;
c i n >> n ;
i f ( nums . count ( n ) ) cout << ”YES” << e n d l ;
e l s e cout << ”NO” << e n d l ;
}
return 0 ;
}
12
Problem M:
Tutorial:
There are 2 methods to solve the hard version of the problem with the new constraint
n ≤ 1018 .
Method 1:
Just like the easier version we preprocess all the possible values, but that would be
O(sqrt(n) ∗ p) which is O(109 · 60) in the worst case, we need to optimize it bit by starting
the preprocess from p ≥ 3 and that would mean the complexity becomes O(n1/3 · 63) and
then after the the preprocessing is done for each testcase we need to check the case if
there exist a k such that 1 + k + k 2 = n which can be done in O(1) using the quadratic
formula and we check if such n value exist in the preprocessed array using binary search.
In case one of the 2 conditions is true then we output YES; otherwise we output NO.
This solution has a complexity of O(106 · 60 + t · log(106 )
Method 2: Pp i
let’s suppose that there exist k > 1 and p ≥ 2 such that: i=0 k = n andsince all
terms are positive we can conclude that k ≤ n and we also know that 1 ≤ Cpi for all
p
0 ≤ i ≤ p if we multiply by k p and take the sum we get pi=0 k p ≤ pi=0 Cpi · k p which is
P P
no other than the binomial expression of (k + 1)p but since p ≥ 2 and k > 1 we can never
get the equality between those 2 terms so the inequality is strict, combining the 2 result
from above weP get:
k p ≤ n = pi=0 k p < (k + 1)p
taking the p-th root from both sides k ≤ n1/p < k + 1 which is by definition the floor
function applied to n1/p so all we have to doP is to iterate over 1 ≤ p ≤ 60 and check each
time if k = ⌊n1/p ⌋ verifies the equation n = pi=0 k p .
The time complexity of this solution is O(t · 602 )
13
Solution 1:
#include<b i t s / s t d c ++.h>
using namespace s t d ;
using LL = long long ;
s e t <long long> nums ;
int main ( ) {
14
Solution 2:
#include <i o s t r e a m >
#include <cmath>
using namespace s t d ;
int main ( )
{
ios base : : sync with stdio (0);
cin . t i e (0);
cout . t i e ( 0 ) ;
int t ;
c i n >>t ;
while ( t −−){
long double n ;
c i n >>n ;
bool bo=f a l s e ;
int r =0;
for ( int k=2;k<=63;k++){
long double q=2;
q=f l o o r ( pow ( n , 1 / ( long double ) k ) ) ;
long double h=1, q1=q ;
for ( int j =1; j<=k ; j ++) {
h+=q1 ;
q1∗=q ;
}
i f ( h==n&&q>1) {
bo=true ;
}
}
i f ( bo&&n>1) cout<<”YES”<<e n d l ;
e l s e cout<<”NO”<<e n d l ;
}
return 0 ;
}
15