Solution
Tutorial is loading...
Code
t = int(input())
for tc in range(t):
n, k = map(int, input().split())
cards = list(map(int, input().split()))
ct = {}
ans = n
for c in cards:
if c in ct:
ct.update({c: ct[c] + 1})
else:
ct.update({c: 1})
if ct[c] >= k:
ans = k - 1
print(ans)
Solution
Tutorial is loading...
Code
t = int(input())
for tc in range(t):
n, m = map(int, input().split())
gr = []
for i in range(n):
gr.append(input())
ans = "YES"
if gr[0][0] != gr[n - 1][m - 1]:
impossible = True
for j in range(m - 1):
if gr[0][j] != gr[0][j + 1] or gr[n - 1][j] != gr[n - 1][j + 1]:
impossible = False
if impossible:
ans = "NO"
impossible = True
for i in range(n - 1):
if gr[i][0] != gr[i + 1][0] or gr[i][m - 1] != gr[i + 1][m - 1]:
impossible = False
if impossible:
ans = "NO"
print(ans)
Solution
Tutorial is loading...
Code
t = int(input())
for tc in range(t):
n = int(input())
a = list(map(int, input().split()))
maxsize = max(a)
a.sort()
mexsize = 1
for sz in a:
if sz == mexsize:
mexsize = mexsize + 1
if mexsize > maxsize:
print("Alice" if maxsize % 2 == 1 else "Bob")
else:
print("Alice" if mexsize % 2 == 1 else "Bob")
1965B - Missing Subsequence Sum
Solution
Tutorial is loading...
Code
t = int(input())
for tc in range(t):
n, k = map(int, input().split())
i = 0
while (1 << (i + 1)) <= k:
i = i + 1
ans = [k - (1 << i), k + 1, k + 1 + (1 << i)]
for j in range(20):
if j != i:
ans.append(1 << j);
print(len(ans))
print(*ans)
Solution
Tutorial is loading...
Code
t = int(input())
for tc in range(t):
n = int(input())
s = input()
mn = 0
mx = 0
cur = 0
for c in s:
if (cur % 2 == 0) == (c == '1'):
cur = cur + 1
else:
cur = cur - 1
mn = min(mn, cur)
mx = max(mx, cur)
print(mx - mn)
Solution
Tutorial is loading...
Code
def getSubarraySums(a):
cts = []
for i in range(len(a)):
sm = 0
for j in range(i, len(a)):
sm = sm + a[j]
cts.append(sm)
cts.sort()
return cts
def getOddOccurringElements(cts):
odds = []
for ct in cts:
if len(odds) > 0 and ct == odds[-1]:
odds.pop()
else:
odds.append(ct)
return odds
def getPalindrome(odds, n):
a = [0] * n
prev = 0
idx = (n - 1) // 2
for x in odds:
if idx == n - 1 - idx:
a[idx] = x
else:
a[idx] = (x - prev) // 2
a[n - 1 - idx] = (x - prev) // 2
prev = x
idx = idx - 1
return a
def getLargestExcluded(bigList, smallList):
while len(smallList) > 0 and bigList[-1] == smallList[-1]:
bigList.pop()
smallList.pop()
return bigList[-1]
t = int(input())
for tc in range(t):
n = int(input())
subarraySums = list(map(int, input().split()))
subarraySums.sort()
odds = getOddOccurringElements(subarraySums)
missingSum = -1
if len(odds) > (n + 1) // 2:
oddvals = []
evenvals = []
for x in odds:
if x % 2 == 1:
oddvals.append(x)
else:
evenvals.append(x)
if len(evenvals) > 0 and len(oddvals) > 0:
missingSum = evenvals[0] if len(evenvals) == 1 else oddvals[0]
else:
b = getPalindrome(odds, n + 2)
bSums = getSubarraySums(b)
y = bSums[-1]
x = getLargestExcluded(bSums, subarraySums)
missingSum = 2 * x - y
else:
b = getPalindrome(odds, n - 2)
bSums = getSubarraySums(b)
y = bSums[-1]
x = getLargestExcluded(subarraySums, bSums)
missingSum = 2 * x - y
odds.append(missingSum)
odds.sort()
odds = getOddOccurringElements(odds)
ans = getPalindrome(odds, n)
print(*ans)
Solution
Tutorial is loading...
Code
n, m, k = map(int, input().split())
a = []
for i in range(n):
a.append(list(map(int, input().split())))
ans = []
for x in range(n):
for y in range(m):
for z in range(1, n + 1):
if y % 2 == 1:
ans.append([x, y, z, a[x][y]])
else:
ans.append([x, y, z, a[min(x, n - z)][y]])
for z in range(n + 1, n + k + 1):
if y % 2 == 1:
ans.append([x, y, z, a[x][y]])
else:
ans.append([x, y, z, z - n])
for x in range(n, n + k):
for y in range(m):
for z in range(1, n + 1):
if y % 2 == 1:
ans.append([x, y, z, x - n + 1])
else:
ans.append([x, y, z, a[n - z][y]])
ans.append([x, y, n + 1, x - n + 1])
for y in range(m):
for z in range(n + 2, n + k + 1):
ans.append([n, y, z, z - n])
for x in range(n + 1, n + k):
for z in range(n + 2, n + k + 1):
ans.append([x, 0, z, max(x - n + 1, z - n)])
print(len(ans))
for cube in ans:
print(cube[0] + 1, cube[1] + 1, cube[2] + 1, cube[3])
Solution
Tutorial is loading...
Code
/**
* author: tourist
* created: 26.11.2023 09:36:38
**/
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#include "algo/debug.h"
#else
#define debug(...) 42
#endif
const long long inf = (long long) 1e18;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int n;
cin >> n;
vector<long long> l(n), r(n);
for (int i = 0; i < n; i++) {
cin >> l[i] >> r[i];
}
int original_n = n;
for (int rot = 0; rot < 2; rot++) {
// make all left ends distinct
map<long long, vector<long long>> mp;
for (int i = 0; i < n; i++) {
mp[l[i]].push_back(r[i]);
}
vector<long long> new_l, new_r;
auto it = mp.begin();
multiset<long long> s;
long long T = -inf;
while (true) {
if (s.empty()) {
if (it == mp.end()) {
break;
}
T = it->first;
}
while (it != mp.end() && T == it->first) {
s.insert(it->second.begin(), it->second.end());
++it;
}
assert(!s.empty());
new_l.push_back(T);
new_r.push_back(*s.begin());
s.erase(s.begin());
T += 1;
while (!s.empty() && *s.begin() < T) {
s.erase(s.begin());
}
}
swap(l, new_l);
swap(r, new_r);
n = (int) l.size();
for (int i = 0; i < n; i++) {
l[i] *= -1;
r[i] *= -1;
swap(l[i], r[i]);
}
}
sort(l.begin(), l.end());
sort(r.begin(), r.end());
vector<long long> ans(original_n + 1);
long long lx = -inf, rx = -inf;
int pl = 0, pr = 0;
int k = 0;
while (pl < n || pr < n) {
long long wait = min(pl < n ? l[pl] - lx : inf, pr < n ? r[pr] - rx : inf);
ans[k] += wait;
lx += wait;
rx += wait;
while (pl < n && l[pl] == lx) {
k += 1;
lx += 1;
pl += 1;
}
while (pr < n && r[pr] == rx) {
ans[k] += 1;
k -= 1;
rx += 1;
pr += 1;
}
}
for (int i = n; i > 1; i--) {
ans[i - 1] += ans[i];
}
for (int i = 1; i <= original_n; i++) {
cout << ans[i] << '\n';
}
return 0;
}
Super Fast Tutorial
Ultralightning fast editorial !!!
Auto comment: topic has been updated by jdurie (previous revision, new revision, compare).
bros made tutorial even before the contest
Nice Super-fast Tutorial
Round #877 editorial?!
oops, fixed it
Thank for so fast tutorial!
Good round. I enjoyed the problems.
why is he getting downvoted I do not understand how this works bunch of crazy people
Very bad problem D!!!
This problem is constructed without providing any information. Most of the time, unless we find out that the lack of information doesn't affect something.But the Problem D in last contest which is Div.1 has difficulty of 2800,why are you angry about not doing it.
A difficulty of 2800 , are you sure? I managed to solve it.
"Div.1" D
Just shows my great reading skills:)
Imo div2 D was actually pretty good. It was construction which is pretty meh but you could solve it by writing things down instead of just guessing so it wasn't so bad.
The unsaid rule on codeforces is —
Able to solve the problem — Wonderful problem,Wonderful contest,Wonderful authors, Thanks the authors in the comments section.
Not able to solve the problem — Crap problem,crap contest,crap authors, comments mathforces adhocforces xyzforces in the comments section.
you got me haha, I would've hated D if I hadn't solved it
on an unrelated note, E was terrible and ad hoc
Was my first comment and ppl demoted me
Can someone who solved Div2-C DP explain his approach please
hey no offense but why do it with DP when there is a pretty simple solution, it involves just counting the number of leading 1's in differences between consecutive elements of array sorted in ascending order.
I didnt use the editorial approach but the idea is similar:
obvious question --> how do I track the number of rocks per move when rocks are being removed from all piles??? --> you can sore the piles as delta difference for each pile and ignore repeating numbers --> now you can simply deduce which valid moves can be made.
after this calculation now you have a delta vector and a base condition that if there is just one pile Alice wins.
The editorial does this much simply by just checking if there is an increasing sequence but I couldnt really get to such a simple solution in the contest.
This is my solution from the contest using recursion with memoization.
First I sort the array and remove duplicates for convenience. In the array dp I remember whether or not the player wins if it's his turn on a certain index. If there is a move that the current player can make such that the opposing player is in a losing position on the next index, then he is in a winning position on the current index. The current player is also in a winning position if he can make it so he is in a winning position on the next index.
It is possible to do both moves if the difference between the current pile and the previous one is greater than 1, so we take both into account. This works because you can leave 1 rock in the current pile and then it is your turn on the next index, or you can take all the rocks and then it is the opponent's turn on the next index. If the difference between the current pile and the previous one is equal to 1 then is impossible to have the next move on the next index, so it is only the opponents.
Look at the code as well, I think it is quite clean.
Div2-C dp solution Initially sort the numbers and remove the duplicates and then take difference with respect to previous element. Now start iterating from backward. We can say that when the the diff is not equal to 1 the first player always wins. but when it is equal to the 1 the player who wins i+1 will lose so dp state is dp[i]=1^dp[i+1] when 1 is diff value at an index, dp[i]=1 when the diff is equal to any value other than 1
Awesome
Can we just talk about how disgustingly simple the code for D2E — Folding Strip looks??
Why are bounds so tight in D1E? My solution only uses 348800, do you think it is a good practice to set bound to 350000 and also make your solution fail?
https://codeforces.me/blog/entry/128935
max = 281150 sol : 258515976
conqueror_of_tourist could you share how you managed to solve C in just 4 minutes? Did you see the problem before? It's hard to believe it could be that easy
If you view the problem as: "construct the smallest possible final strip such that you can create a 'walk' on the strip that corresponds to the original string", then you can see that any repeated 00 or 11 is 'suboptimal'. From there there's only one possible string you can create and you can simulate it.
Of course, formally proving that the final string cannot contain any 00s or 11s is harder (and I eventually did it using the same solution as the editorial) however for my original submission I just used 'proof by AC' after it passed the samples.
I see, that's really impressive! Thanks for the explanation :)
Awesome contest, almost got Div2 D, will get it next time! Thanks for the super fast tutorial.
Great problem 1E! However, I am still unclear about the optimality proof for problem 1C. Is there a more intuitive or formal explanation for "composing" the valid foldings?
I thought, if you have three consecutive characters you can "merge" them into 1 by doing the zig-zag fold. By doing this repeatedly you end up with a string with maximally 2 consecutive characters. Also it's never bad to do this because if there was an optimal folding which contained an overlap between more than 2 consecutive characters, both sides of the fold could be merged, resulting in a better solution. When the max number of consecutive characters is 2, I felt like it was pretty intuitive that you should always fold between the consecutive pairs because it always works and you do maximum folding.
Oh, I have a simple idea: If a string t has consecutive same characters, it's always possible to apply the greedy folding algorithm again and obtain a strictly shorter string. Another folding is intuitively always possible, I think this is what "compose" means.
Is there a category for the game problems "Alice" & "Bob" play optimally?
How do I improve on these problems?
Nim games (Game theory) — gfg link
That problem litterally had nothing to do with nim.
It would probably give him insight and confidence for these problems, when I read "nim" in an easy problem, I feel confident lol!
I read about it through it's Wikipedia article and got some idea about strategy games.
Also the idea of transitioning positions at will comes up in a lot of problems.
true.
I solved the problem pretty naively applying grundy nums 258426128.
You should try to find out when someone has control over the rest of the game the one who does wins the rest doesnt matter thats how i solved C
The CF problems usually don't require any knowledge other than basic math and number theory, these are called game theory problems, when you're trying to play optimally as bad ur opponent plays is called Maximin strategy, the kind of game where the participants remove objects, etc is called nim games, which for CP, in general, there is no need other than just simple logic + math.
Learn the “plus-minus” principle (retroanalysis of the game).
How to force player to play the only possible bad move
If number of piles remaining is 1 pick all which means you won else pick exactly min-1 forcing the opponent just one option that is picking up 1. You will win as long as you are not forced to pick just one stone which leads to the increasing sequence logic. Hope this helps!
It wasn't a question lol :)
if I'm not mistaken, problem B can be solved in O(n+m) 258432155 the solution is quite long, but still
Taking input is O(nm).
oh, yeah... sounds logic
thank you
or may be like this 258432643
What should be the general thought process while approaching problems like Div2-D/ Div1-B?
I was trying to come up with some constructions on paper but every time I got stuck on the same idea, nothing special was popping out. What should be done when stuck like this?
To solve problems like Div2-D one must always try to see the problem using different perspectives especially when it is less intuitive. In other words, if one approach doesn't work then jump to other approaches. I tried to solve using greedy and dp but could not do it.
it says: you want have every possible sum, how? One way is to have n ones. but something else, there is always a way to represent a number as the sum of powers of 2, so you think of log and power 2-based solution, now the main point is how to tweak those powers of 2 such that, there won't be a possible sum but others will be possible, there is a trap I fell into in the contest time:
which may be possible but requires a lot of case forking on the set bits in k.
there is also another important observation, $$$k = k/2 + k/4 + \cdots$$$
$$$A = k/2 + k/4 + k/8 + \cdots \newline 2*A = k + k/2 + k/4 + \cdots \newline 2A - A = k \newline => A = k$$$
which with a little bit of tweaking with the math, you get that you can go from $$$(k-1)/2$$$ to $$$1$$$ and $$$k+1$$$ to $$$2*n$$$, using multiplying by 2. which will give you the solution, now there is left to prove that you can create anything, but k.
which is the proof represented in the editorial
I hope this was helpful to let you understand the intuition to how to get the solution.
Always use pen and paper during the contest, even if u don't write anything, it'll help you adjust your mind
For Problem B, why are test cases 6 and 8 NO? For example, test case 8 "WBBWB", we can select 2nd cell B, all the way to last cell B and color all white to end with "WWWWW" or alternatively, select 1st cell W and 4th cell W and color all black.
Similarly, test case 6, we could select either the upper black square or the lower white square and color it to match the other one. BB BB WW WW
Read the Question Once Again
You should read this ...
The color you fill the rectangle with is the color that the cells you select are.
i'm pretty sure c is 1300 but i failed badly :(
For Div2 C, what should be the answer for testcase: [1, 3, 5]
According to me it should be "Bob", if I'm wrong please explain.
Yes, correct answer is Bob
it's a really fast tutorial, but why most codes in python?
if you add c++ I will be thankful!
Could someone try to hack my solution for D?
https://codeforces.me/contest/1966/submission/258465640
I failed...
it is so correct.
Yeah, after covering [1, 4x + 1] and using all the bits except $$$2^i$$$ it is actually correct.
man if the contest was 5 more minutes I'd solved D :)
I also got the idea in the last few minutes, but luckily solved 2 minutes before contest ended
Man! orz
can you explain your code please
Sorry, I don't know how to explain my code in an intuitive way.
Consider n = 6, k = 1.
k-1 = 0, so you won't add anything.
Then add k+1, i.e. 2.
Now, next powers of 2 that are greater than k but <=n is 4.
So, in total you have {2,4}. You can't get a subsequence of sum 3 from this.
I honestly can't see why my solution is failing. Shouldn't it give the same answer as solution in the editorial? 258438670
I got it, nevermind
Very fast editorial. Thanks!
what a beautiful profile picture
"C" you the next time
Does problem 2D has any other more intuitive solution and can anybody explain it please
I took 2k, 4k, 8k... until 2^i*k is less than n, I also took 3k; also another k+1; then to be able to make all the numbers smaller than k:
So we have numbers from 1 to k-1, if we add k+1 we have all from k+2 to 2k
2k,4k,8k.. helps us to get any M*k, if M is odd we can take 3k add this to (M-3)*k
If we use it, we can make all M*k+x, x<=k-1
thanks man
First time competitor here. Solved D2D post-round.
I wasn't fully confident in the "descending from k" strat for the bottom part, went ascending from 1. Add powers of 2 starting from 1, stop when the next sum would be >= k, then add such a number to obtain a sum of k-1.
The >k part I did exactly as you wrote (shouldn't it say 2^i*k greater than n?).
Thanks for the tasks. But actually disappointed with С. I don't like such tasks
Another approach in 1B for obtaining subset sums in interval $$$[0;k)$$$. Let us say that by induction we can build a set of numbers such that its subset sums make an interval of $$$[0; \frac{k+1}{2})$$$. Now if we add $$$\frac{k}{2}$$$ to that set we can make an interval of $$$[0; k)$$$. So we just always add rounded down $$$\frac{k}{2}$$$ to the set and replace $$$k$$$ with rounded up $$$\frac{k}{2}$$$ until $$$k$$$ equals 1.
minecraft is useable to create edtiorial picture of D1E.
div 2d is not very intuitive to me but it seems that a lot of people have used different approaches, can someone tell me their thought process , i dont care about the proof but how people came to the conclusion is what i want to know.
For Div2D proof
If v>k, we can take k+1 along with the binary representation of v−k−1
Can't understand how it is possible to take the binary representation of v-k-1?
if v>k there are two cases for v-k-1 Case 1: v-k-1 does not have ith digit on,in that case we already have all the power of 2 from 0 to 19 except i so v-k-1 can be easily obtained by combining those numbers; Case 2: v-k-1 have ith digit on, in that case lets remove the ith digit by subtracting (1<<i) from it ,hence instead of subtracting k+1 from v , we subtract k+1+(1<<i) , now v-k-1 has turned to case 1 because we have already removed ith digit.
I have a slightly different solution of 1965B - Missing Subsequence Sum.
If you know subset sum using Bitset, then it is way easier to visualize.
Let $$$bs$$$ be a Bitset of size $$$n + 1$$$. $$$bs[i]$$$ is true if we can get a sum of $$$i$$$ using some elements in $$$a$$$.
Now, if we add another element $$$x$$$ in $$$a$$$, the bitset would change accordingly.
Since we choose the value of $$$x$$$, we can control which bits we want to be set.
Initially, only $$$bs[0] = true$$$ and all other $$$bs[i] = false$$$.
Eventually, we want only $$$bs[k] = false$$$, and all other $$$bs[i] = true$$$.
At each step, we'll choose $$$x$$$ such that we can set as many unset bits as possible, without setting the k-th bit.
For example: Let $$$n = 15$$$ and $$$k = 6$$$.
$$$bs = 0000000000000001$$$ (The LSB $$$bs[0]$$$ is at the right)
So choose $$$x = 1$$$.
$$$bs = 0000000000000011$$$
Choose $$$x = 2$$$
$$$bs = 0000000000001111$$$
Choose $$$x = 2$$$, that'll set all bits before the k-th bit.
$$$bs = 0000000000111111$$$
Choose $$$x = 7$$$
$$$bs = 0001111110111111$$$
Choose $$$k = 13$$$
$$$bs = 1111111110111111$$$
For this example, it was enough. But if you notice, on adding $$$x (> k+1)$$$ in $$$a$$$, $$$0$$$ will be present at the $$$(x+k)-th$$$ bit.
On further observation, you can see that the gap between the zeros is $$$2k + 1$$$ (if not handled).
Because we are repeating a pattern of $$$k$$$ 1s, 0, $$$k$$$ 1s. So there are $$$2k$$$ 1s between two 0s.
So a final addition of $$$x = k + 1$$$ is enough to set all those unset bits.
My Submission: 258434678
I wonder if that's how the checker is also built.
thats a damn cool solution bro
could you explain the implementation ?
Felt kinda frustrated after proof-by-ACing C, but not anymore after reading the intended solution. It’s an extremely clever problem, thanks for the contest!
Hi!
I am not able to understand editorial for Problem: Everythin Nim. Can anyone explain me in simpler terms?
Thanks in advance.
First observe that when the smallest pile contains 1 then the player is forced to choose 1. Thus it is a forcing move. Now remove all the duplicates in array and sort it in ascending order, as this does not affect the answer.
Now consider the case when no consecutive numbers in the new array have a difference of 1 between them. You will see that when a person is forced to move (that is, the least pile is 1 in the person's chance), he/she will definitely lose.
Now let's focus on the case when there are is some sequence of consecutive numbers starting from the least element.
Case 1 -> they start from 1. For eg: 1 2 3 4 8 9 .... In this case Alice can convert this to 1 8 9 .... for Bob. Hence Alice wins. eg2: 1 2 3 8 9.... In this case Alice will only be able to convert this to 1 8 9... for herself. Hence she loses.
Case 2 -> they do not start from 1. For eg: 2 3 4 5 8.. In this case Alice always wins because she can convert this situation to 1 2 3 6... for bob and the situation 2 3 4 8 to 1 2 3 7 for Bob.
Hence we have covered all the cases. You can see my code for more clarity. You will have to try these examples yourself and convince yourself.
I’m not one to judge a contest or problems. On average, they were good, but Div2D/Div1B was a bit lucky if you wrote things down or used brute force. It felt like guessing sometimes. Personally, I implemented a constructive/brute force solution using a bitset, similar to knapsack optimization.
Thanks for the contest!
Can anyone explain me question C?
1965D — Отсутствующая сумма подмассива? Hmm, probably you need to fix this (in English Version)
Nice Turorial
Div1 B has a different approach:
First, we construct a sequence $$$a$$$ containing $$$1,2,4,8\dots 2^l,v$$$. The sum of those integers in the sequence is equal to $$$k-1$$$. It can be proved that for every integer $$$i\in [1,k-1]$$$, there exists a subsequence of $$$a$$$ with a sum of $$$i$$$.
Next, consider finding the smallest integer that can't be presented as the sum of a subsequence of $$$a$$$. After finding such integer (Let it be $$$s$$$), append $$$s$$$ to the end of $$$a$$$. This can be done using knapsack dp.
This approach comfortably fits in the limits.
258500094
DIV 1 A: what will be the answer if test
1
6
1 3 4 6 9 15
from the tutorial: it is Bob but what if if we do like below:
After Alice : 2 3 5 8 14
After Bob: 1 3 6 12 ( as bob sees that winning state)
after alice: 2 5 11
after bob : 3 9 (as bob sees winning state)
after alice: 1 7 (as not winning state)
after bob: 6
after alice: []
so why not alice is winning here?
When the condition is "2 5 11" and it is Bob's turn, Bob can choose $$$k = 1$$$ and the stones will be "1 4 10". Now Alice must choose $$$k = 1$$$ and the stones will be "3 9". Then Bob can choose $$$k = 2$$$ and it will be "1 7". So Alice has to choose $$$k = 1$$$ and there will be only one pile of stones which has 6 stones. It means that Bob can remove all of them and win the game.
I think the key of this problem is when the least number of stones is $$$1$$$, the player who should remove some stones does not have any choice but let $$$k = 1$$$. So Alice and Bob should jump out of this "rule" and force each other to be trapped in this "rule".
Hope to help you.
:D
Thanks. I have understood
Thanks for the amazing tutorial !!! It helped me for the questions I couldn't solve.
Video solution for Folding Strip (Div2 E) (Hindi)
Really good editorial especially for D
here is my dp solution for problem c https://codeforces.me/contest/1966/submission/258437818
I'm interested in problem missing subsequence sum. The proof is understandable but hard to come up with the solution during contest. Do you have any other similar problem like that?
Yes, try CF1922E : Increasing Subsequences
I've solved it yet couldn't intuitively solve missing subsequence sum problem :(. Do you have more problem similar to that?
.
The solution of CF1965E is so ingenious OMG. How can you grandmasters bethink of it??!
Which problem was the one from the yandex cup
First problem was really good.
hello
why can't we apply the solution of game of nim in the question everything is nim ? As game of nim solution (Buton's theorem) states that if XOR of all the values in all piles is zero then bob will win else alice will win.