We at GDG IIITA are extremely delighted to have successfully hosted AlgoArena 2025. We want to extend our heartfelt gratitude to each and every one of you for participating in AlgoArena, our flagship coding event. Your enthusiasm, dedication, and creativity have made this event a remarkable success. We hope you enjoyed solving the questions as much as we enjoyed creating them for you.
A: Squid Game
Idea:rndascode
Can you think of extending the logic for a normal stone paper scissor game to get the solution?
What if we check for a solution by first retracting the left hand and then the right hand? Then each checking becomes same as checking for normal stone paper scissor game.
To solve the problem, follow these steps:
Key Observations
If Ritesh retracts his left hand (
L1
), his remaining hand (L2
) will compete against Aaryan's hands (L3
andL4
).If Ritesh retracts his right hand (
L2
), his remaining hand (L1
) will compete against Aaryan's hands (L3
andL4
).For each scenario, compare Ritesh's remaining hand with both of Aaryan's hands:
- Ritesh wins if his symbol beats Aaryan's symbol.
- Ritesh loses if Aaryan's symbol beats his.
- The result is a draw if both symbols are the same.
Decision Process
- If Ritesh can avoid losing against both of Aaryan's hands by retracting either hand, output
Left
. - If Ritesh can avoid losing by retracting only one specific hand, output
Left
orRight
, depending on the safe choice. - If both scenarios result in at least one loss, output
Impossible
.
#include <iostream>
#include <string>
using namespace std;
string determineOutcome(char r1, char a1) {
if (r1 == a1) {
return "Draw";
} else if ((r1 == 'R' && a1 == 'S') || (r1 == 'S' && a1 == 'P') || (r1 == 'P' && a1 == 'R')) {
return "Win";
} else {
return "Lose";
}
}
int main() {
int t;
cin >> t;
while (t--) {
string s;
cin >> s;
char rLeft = s[0];
char rRight = s[1];
char aLeft = s[2];
char aRight = s[3];
string outcomeLeft1 = determineOutcome(rRight, aLeft);
string outcomeLeft2 = determineOutcome(rRight, aRight);
string outcomeRight1 = determineOutcome(rLeft, aLeft);
string outcomeRight2 = determineOutcome(rLeft, aRight);
bool leftSafe = (outcomeLeft1 != "Lose" && outcomeLeft2 != "Lose");
bool rightSafe = (outcomeRight1 != "Lose" && outcomeRight2 != "Lose");
if (leftSafe && rightSafe) {
cout << "Left" << endl;
} else if (leftSafe) {
cout << "Left" << endl;
} else if (rightSafe) {
cout << "Right" << endl;
} else {
cout << "Impossible" << endl;
}
}
return 0;
}
B: Binary Step Down
Idea:pranavsingh0111
We need to convert all ones to zeroes .
After each operation, what changes happen to the 1's present in the string? Try writing out a few examples in binary and observe the pattern .
Look carefully at how $$$X$$$ $$$\text&$$$ $$$(-X)$$$ affects different positions .
Can any 1 except the rightmost one be changed by applying one operation?
Only the right-most 1 is converted to 0 after applying one operation. So it is easy to say that the answer to the question is simply the number of 1's in the binary representation .
But why only the right most 1 ??
Let $$$X$$$ be any binary string , for example —
$$$X$$$ = $$$1101.....10000$$$
then $$$(-X)$$$ will be calculated as follows —
Flipping the bits , we get — $$$0010.....01111$$$
Now adding 1 we get — $$$0010.....10000$$$
So $$$X = 1101.....10000$$$ and $$$(-X) = 0010.....10000$$$ , we can now easily see that all the bits on the left side of the right most 1 are opposite in $$$X$$$ and $$$(-X)$$$ , so $$$ X \text& (-X)$$$ will be equal to $$$0000.....10000$$$ and subtracting it will convert the rightmost $$$1$$$ to $$$0$$$ .
#include <bits/stdc++.h>
using namespace std ;
#define int long long
#define endl '\n'
void solve(){
string s ;
cin >> s ;
int n = s.size() ;
int ans = 0 ;
for(int i=0 ; i<n ; i++){
if(s[i]=='1'){
ans++ ;
}
}
cout<<ans<<endl;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 1 ;
cin >> t ;
while(t--){
solve();
}
}
C: Lost Element
Idea: pranavsingh0111
Consider inserting a value $$$x$$$ between two numbers $$$a$$$ and $$$b$$$.
Original contribution to score: $$$|a-b|$$$
New contribution after insertion: $$$|a-x| + |x-b|$$$
For score to remain same: $$$|a-b| = |a-x| + |x-b|$$$
This is the triangle inequality!
For each possible position $$$i$$$, we need numbers that work between $$$a[i]$$$ and $$$a[i+1]$$$ This gives us ranges $$$[\min(a_i,a_{i+1}), \max(a_i,a_{i+1})]$$$ for each position.
Now we just need to find the union of all such intervals. But do we actually need to manually calculate the union ? What observation can be made about the union of all such intervals ?
One observation that we can make is that the union of ranges $$$[\min(a_i,a_{i+1}), \max(a_i,a_{i+1})]$$$ and $$$[\min(a_{i+1},a_{i+2}), \max(a_{i+1},a_{i+2})]$$$ is simply $$$[\min(a_i,a_{i+1},a_{i+2}), \max(a_i,a_{i+1},a_{i+2})]$$$
Similary we can say that union of ranges , $$$[\min(a_i,a_{i+1}), \max(a_i,a_{i+1})]$$$ , $$$[\min(a_{i+1},a_{i+2}), \max(a_{i+1},a_{i+2})]$$$ and $$$[\min(a_{i+2},a_{i+3}), \max(a_{i+2},a_{i+3})]$$$ is $$$[\min(a_i,a_{i+1},a_{i+2},a_{i+3}), \max(a_i,a_{i+1},a_{i+2},a_{i+3})]$$$ and so on .
So for the complete union , we get —
Required Interval = $$$[\min(a_i,a_{i+1},...,a_n) , \max(a_i,a_{i+1},...,a_n)]$$$
And Number of elements in this interval = MaxElement — MinElement + 1
#include <bits/stdc++.h>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
#define int long long
#define endl '\n'
typedef tree<int, null_type, less<int>, rb_tree_tag, tree_order_statistics_node_update> pbds; // *find_by_order, order_of_key
void solve(){
int n ;
cin >> n ;
vector<int> arr(n-1) ;
for(int i=0 ; i<n-1 ; i++){
cin >> arr[i] ;
}
int mx = *max_element(arr.begin(), arr.end()) ;
int mn = *min_element(arr.begin(), arr.end()) ;
cout<<mx+1-mn<<endl;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 1 ;
cin >> t ;
while(t--){
solve();
}
}
D: Parity Operations
Idea: rndascode
Can the parity p ever change, irrespective of how we choose $$$a$$$ and $$$b$$$?
When is the initial parity p odd?
Initial Sum Parity:
- The sum of the first $$$n$$$ natural numbers is given by:
- For $$$S$$$ to be odd, $$$n(n+1)$$$ must be divisible by $$$2$$$ but not by $$$4$$$. This happens when $$$n$$$ leaves a remainder of $$$1$$$ or $$$2$$$ when divided by $$$4$$$.
Parity Preservation:
- During each operation, the sum $$$S$$$ changes as:
- This is same as decreasing $$$S$$$ by $$$2 * $$$ min($$$a,b$$$), which will always be even. Thus if $$$S$$$ was initially odd, then odd — even = odd. Thus, the parity of the sum remains unchanged after each operation.
To solve the problem, we need to check if the initial sum $$$S$$$ is odd. This happens if and only if $$$n$$$ leaves a remainder of $$$1$$$ or $$$2$$$ when divided by $$$4$$$. For each test case, we can compute $$$n$$$ mod $$$4$$$ and check if the result is $$$1$$$ or $$$2$$$.
#include <bits/stdc++.h>
using namespace std;
#define int long long
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
int t;
cin >> t;
while (t--) {
int n;
cin >> n;
if (n % 4 == 1 || n % 4 == 2)
cout << "YES" << endl;
else
cout << "NO" << endl;
}
return 0;
}
E: Find the Array
Idea: pranavsingh0111
For any index $$$i$$$:
$$$A[i] + B[i]$$$ = ($$$Ans[i]$$$ $$$|$$$ $$$Ans[i+1]$$$) + ($$$Ans[i] \text& Ans[i+1]$$$) = $$$Ans[i] + Ans[i+1]$$$
Since $$$n$$$ is odd , can you find the value of any one element of $$$Ans$$$ ?
Let $$$S = \sum_{i=1}^n A[i] + B[i]$$$
We know that $$$A[i] + B[i]$$$ = $$$Ans[i] + Ans[i+1]$$$
So $$$S = (Ans[1] + Ans[2]) + (Ans[2] + Ans[3]) + ...... + (Ans[n] + Ans[1]) $$$
or $$$S = 2 \sum_{i=1}^n Ans[i]$$$ (each element appears twice in sum)
or $$$SUM$$$ = $$$S/2$$$
Now we need to find the value of any one element of $$$Ans$$$ , we then know the value of $$$(Ans[i] + Ans[i+1])$$$ , so if we get any one value , we can the value of $$$Ans[i+1]$$$ easily .
Let $$$X = (A[2] + B[2]) + (A[4] + B[4]) + ..... + (A[n-1] + B[n-1])$$$
Note that since n is odd , \bf{n-1 will always lie in this series} as it will be even .
So $$$X = Ans[2] + Ans[3] + Ans[4] + Ans[5] + ..... + Ans[n-1] + Ans[n] $$$
Now , Using the value of $$$SUM$$$ and $$$X$$$ , we get $$$Ans[1] = SUM - X$$$
Now we can get the rest of the elements by simple substitution .
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define endl '\n'
void solve(){
int n ;
cin >> n ;
vector<int> A(n) , B(n) , Ans(n,-1) ;
for(int i=0 ; i<n ; i++){
cin >> A[i] ;
}
for(int i=0 ; i<n ; i++){
cin >> B[i] ;
}
int totalSum = 0 ;
for(int i=0 ; i<n ; i++){
totalSum += (A[i] + B[i]) ;
}
totalSum /= 2 ;
// x stores ans1 + 2*ans2 + ans3
int x = (A[0] + B[0]) + (A[1] + B[1]) ;
//adding ans4 + ans5 + ans6 ... + ansn
for(int i=3 ; i<n ; i+=2){
x += (A[i] + B[i]) ;
}
// now x contains ans1 + 2*ans2 + ans3 + ans4 + ans5 + ans6 ... + ansn
Ans[1] = x - totalSum ;
Ans[0] = (A[0] + B[0] - Ans[1]) ;
for(int i=1 ; i<n-1 ; i++){
int sum = A[i] + B[i] ;
Ans[i+1] = sum - Ans[i] ;
}
for(int i=0 ; i<n ; i++){
int first = i , second = (i+1) % n ;
int check1 = (Ans[first]|Ans[second]) ;
int check2 = (Ans[first]&Ans[second]) ;
if(check1!=A[i] || check2!=B[i]){
cout<<-1<<endl;
return ;
}
}
for(int i=0 ; i<n ; i++){
cout<<Ans[i]<<" ";
}cout<<endl;
}
signed main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
int t = 1 ;
cin >> t ;
while(t--){
solve();
}
}