HP18 - EDITORIAL

PROBLEM LINK:

Practice
Contest: Division 1
Contest: Division 2

Setter: Hruday Pabbisetty
Tester: Xiuhan Wang
Editorialist: Taranpreet Singh

DIFFICULTY:

Simple

PREREQUISITES:

Game-Theory and Basic Math would do.

PROBLEM:

Given an array A containing N elements, on which Bob and Alice are playing a game with Bob playing first, both of them having lucky numbers a and b respectively. In one move, a player can remove any number of elements from the array A which are divisible by their lucky number. The player unable to remove any element loses the game. Find winner of the game if both players play optimally.

SUPER QUICK EXPLANATION

  • If A contains elements which are divisible by both a and b, It is optimal for Bob to delete all such elements in the very first move. Turn goes to Alice.
  • Now, it is optimal for both players to remove exactly one number they can remove, until one of the players is unable to make a move, thus losing the game. The number of moves Bob can make is Number of elements divisible by a after deleting numbers divisible by both a and b. Same way for Alice.

EXPLANATION

First of all, let us classify the numbers present in the array into four categories.

  • Numbers divisible by both a and b.
  • Numbers divisible by a but not b.
  • Numbers divisible by b but not a.
  • Numbers not divisible by a or b.

Let Number of elements of the second type be the number of reserve moves of Bob and Number of numbers of the third type be Number of reserve moves of Alice.

Since Bob is having the first move, it is ideal for Bob to remove all elements of the first type in the first move itself to force Alice to use reserve move in next move, if the array contains any number of the first type. This is because if after Bob’s move, if there are any number of the first type present in the array, Alice can remove all of them, forcing Bob to use his reserve move in next move.

Now, the player having lesser reserve move loses since that player shall run out of moves. In case both players had the same number of reserve moves, the player first to move shall lose (After removing numbers of the first type).

It can be easily implemented by making two counter variables counting reserve moves of each player, and a flag determining whether there are any numbers of the first type in the array.

Time Complexity

Time complexity is O(N) per test case.

AUTHOR’S AND TESTER’S SOLUTIONS:

Setter’s solution
Tester’s solution
Editorialist’s solution

Feel free to Share your approach, If it differs. Suggestions are always welcomed. :slight_smile:

1 Like

@admin This problem also do not have access to view! Please make all problem solutions of January long challenge public.

This part of the editorial was very confusing: “In case both players had the same number of reserve moves, the player first to move shall lose (After removing numbers of the first type).”. But thanks for the editorial. my solution

1 Like

can somebody help me.
what is wrong in my solution
https://www.codechef.com/viewsolution/22179724

Talked to admin. Links now working, refresh the page.

can you help me with my code??
i m getting only 18 points

#include<bits/stdc++.h>
#include
#define mod 1000000007
#define ll long long
using namespace std;
int main()
{
int t;
cin>>t;
while(t–)
{
ll n,a,b,k;
cin>>n>>a>>b;
vector v;
ll bob=0,alice=0,both=0;
for(ll i=0;i<n;i++)
{
cin>>k;
if(k%a==0)
bob++;
if(k%b==0)
alice++;
if(k%a==0 && k%b==0)
both++;
}
if(bob>alice)
{cout<<“BOB”<<endl;}
else if(bob<alice)
{cout<<“ALICE”<<endl;}
else if( bob==0 && alice==0)
{cout<<“ALICE”<<endl;}
else if(bob==alice && both==bob)
{cout<<“BOB”<<endl;}
else if(bob==alice && both<bob)
{cout<<“BOB”<<endl;}
}
return 0;
}

#include <bits/stdc++.h>//solution by abhijay mitra
#define ll long long int
#define ibs ios_base::sync_with_stdio(false)
#define cti cin.tie(0)
using namespace std;
#define watch(x) cout << (#x) << " is " << (x) << endl
int main(){
ibs;cti;
int T;ll n,a,b=0;
cin>>T;cout<<"\n";
while(T–){
cin>>n>>a>>b;ll temp;ll count2=0,counta=0;ll countb=0;
for (int i = 0; i < n; ++i){
cin>>temp;
if (!(temp%a)||!(temp%b)){
if (!(temp%(a*b))){
count2++;continue;
}
if (!(temp%a))
counta++;
else countb++;
}
}
if (!count2)
counta–;
if (counta>=countb)
cout<<“BOB\n”;else cout<<“ALICE\n”;

            //we remove the highest multiple of a*b if avavilabe
            //otherwise we remove a or b's multiple
}
return 0;

}

@taran_adm @taran999 @taran_1407 @abhj @hruday968
I think for the test case: 5 4 2 1 2 4 8 16
Answer should be “ALICE”,but your code is giving “BOB”.
Explanation: Lets say,
CASE 1:First move:Bob removes 4,8,16; then [1,2] are left,
Second move: ALICE removes 2; then [1] is left,BOB can’t remove anything now,ALICE WINS.

CASE 2:First move:Bob removes 4,16; then [1,2,8] are left,
Second move: ALICE removes 2,8 ; then [1] is left,BOB can’t remove anything now,ALICE WINS.
SIMPLYFYING,ALICE has lucky number 2 he will not leave anything for BOB in his move…
Any help will be highly appreciated,as still the solution gets Accepted,without considering this test case.

1 Like

Editorials Solution
void solve(int TC) throws Exception{
int n = ni(), a = ni(), b = ni();
boolean f = false;int ca = 0, cb = 0;
for(int i = 0; i< n; i++){
long x = nl();
if(x%a ==0 && x%b ==0)f = true;
else if(x%a==0)ca++;
else if(x%b==0)cb++;
}
if(f)ca++;
pn((ca>cb)?“BOB”:“ALICE”);
}
1
4 2 4
4 8 16 20
According to editos solution Bob will won but here ALICE will win.
Bob starts 4 removed …[8,16,20]
A 8 …[16,20]
B 16 …[20]
A 20 …[]
B nothing to remove
am I making some mistake here?

https://www.codechef.com/viewsolution/59145565

my approach, just kept a counter of number of numbers divisible by alice, bob and both. if alice-both was greater or equal to bob-both, then ALICE wins, else BOB.

I think I too made the same mistake. You don’t have to check if the common numbers between Bob and Alice are removed by whom (which I think you are trying to find out by doing %2). In the question, one person can remove more than one element a one time so Bob will try to remove as much of common elements as possible so that Alice cannot use them any further.
Try with this in mind I am sure you will get your answer.
If you want to check out my code here is the link:
https://www.codechef.com/viewsolution/61566614

1 Like

test this case.
2
3 2 3
6 12 18
4 2 3
6 12 18 24

it should be tell this.
BOB
ALICE

but it doesn’t. why?
this problem is abnormal.

The question is easy , however the language should be clear that one player at one time can remove more than one number in his chance

2 Likes

can someone check what is wrong with my code it only passed the partially :frowning:

https://www.codechef.com/viewsolution/68061389

in each turn they can remove a single non zero element

my answer is comming alice —
common is 2 , 4 and bob is 4,8,16 (3)and alice = 2 ,4,8,16 (4)
now common>0 so bob ++ = bob = 4
since bob == alice so alice is winner
this is my code –

#include

#include

#include

#include

using namespace std;

#define ll long long int

int main(){

ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);      //this is fast I/O (inputput output) use header file <cstdio>

ll t;cin>>t;

while(t--){

    int n,a,b; cin>>n>>a>>b;

    int arr[n];

    for(int i=0; i<n; i++)

        cin>>arr[i];

    int common=0, count1=0, count2=0;

    for(int i=0; i<n; i++){

        if(arr[i]%a==0  && arr[i]%b==0)

            common++;

        else if(arr[i]%a==0)

            count1++;

        else if(arr[i]%b==0)

            count2++;

    }

    if(common>0)

        count1++;

   

    if(count1>count2)

        cout<<"BOB"<<endl;

    else

        cout<<"ALICE"<<endl;

}

return 0;

}