Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Forget the variable names after every move. A state is just the sorted AP with upper limit .
Classify legal moves by which sorted element you increase. The largest can never move. The middle has exactly one possible target. The smallest has at most two possible targets.
Use slack . The three transitions are: if is even, go to diff with the same slack; if , go to the same diff with slack ; if , go to diff with slack .
Write where is odd, and set . The remainder of modulo is irrelevant, so the Grundy value is some .
The sequence is periodic with period . Build one period recursively: ; the lower half maps and nonzero values to ; the upper half maps and . Then only prefix-xor this periodic sequence.
Reduce One Game
Sort the current triple as . The labels are not sacred after a move; if you treat them like permanent names, the problem starts lying to you. Sort after every move.
Now classify what can happen when one number is increased.
Let
be the slack above the current largest element. The start position disappears from the game. Nice. A state is determined by , and the moves are:
Let be the Grundy value.
Strip The Odd Part
Write
where is odd. Also write with .
Every threshold and subtraction is a multiple of the current difference, hence a multiple of . The remainder never affects which moves exist and never changes. So the Grundy value only depends on and :
.
The recurrence is
legal options , where the options are:
For , this gives : odd slack-blocks win, even ones lose.
The Periodic Word
Define a word of length , where inside one period.
Base:
.
For , build from :
Why? In the lower half , the same-diff and double-diff moves are not initially available, so the only important move is to . The mex of one value is exactly map .
In the upper half, write . The halve move gives and the same-diff move gives the lower-half value . The mex of those two values is exactly map .
For later periods, the wrapped same-diff move and the double-diff move show up, but they do not change the mex. This is just a tiny three-value check over : the extra values are never equal to the candidate mex. So really is periodic with period , and the construction above is valid.
That means a single Grundy value can be computed by reading the low bits of : start from , then apply or depending on each next bit.
XOR Over A Huge Range
For one series, runs from to . Since the initial largest is , the slack is
$t=x-c.
Let the initial difference be .
All with the same have the same Grundy value. Since is odd, every complete block contributes one copy of that value to the XOR.
For prefix :
So
xor if the partial length is odd.
Now we only need prefix XORs of .
Each full period of has XOR . For the remainder inside one period, recursively compute only the parities of how many s, s, and s appear in the prefix. The same maps and transform those parities. The XOR of such a prefix is then:
Everything is per input line. The final answer is the XOR of all individual games. Nonzero means Bug wins; zero means Feature wins. Same old Sprague-Grundy tax, just with more bit nonsense than anyone asked for.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
array<int, 3> mapA(array<int, 3> c) {
return {c[1] ^ c[2], c[0], 0};
}
array<int, 3> mapB(array<int, 3> c) {
return {0, c[2], c[0] ^ c[1]};
}
array<int, 3> prefCnt(int k, ll len) {
if (len <= 0) return {0, 0, 0};
ll period = 1LL << (k + 1);
if (len >= period) return {1, 1, 0};
if (k == 0) return {1, 0, 0};
ll half = 1LL << k;
if (len <= half) return mapA(prefCnt(k - 1, len));
array<int, 3> res = {1, 1, 0};
array<int, 3> add = mapB(prefCnt(k - 1, len - half));
for (int i = 0; i < 3; i++) res[i] ^= add[i];
return res;
}
int prefixWordXor(int k, ll len) {
if (len <= 0) return 0;
ll period = 1LL << (k + 1);
int ans = (len / period) & 1LL;
ll rem = len % period;
auto c = prefCnt(k, rem);
if (c[1]) ans ^= 1;
if (c[2]) ans ^= 2;
return ans;
}
int grundyValue(int k, ll s) {
int v = s & 1LL;
for (int i = 1; i <= k; i++) {
if ((s >> i) & 1LL) {
v = (v == 2 ? 1 : 2);
} else {
v = (v == 0 ? 1 : 0);
}
}
return v;
}
int prefixGameXor(ll d, ll T) {
if (T < 0) return 0;
int k = __builtin_ctzll((unsigned long long)d);
ll odd = d >> k;
ll s = T / odd;
ll rem = T % odd;
int ans = prefixWordXor(k, s);
if ((rem + 1) & 1LL) ans ^= grundyValue(k, s);
return ans;
}
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n;
cin >> n;
int xr = 0;
while (n--) {
ll a, b, c, l, r;
cin >> a >> b >> c >> l >> r;
ll d = b - a;
xr ^= prefixGameXor(d, r - c);
xr ^= prefixGameXor(d, l - c - 1);
}
cout << (xr ? "Bug" : "Feature") << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
array<int, 3> mapA(array<int, 3> c) {
return {c[1] ^ c[2], c[0], 0};
}
array<int, 3> mapB(array<int, 3> c) {
return {0, c[2], c[0] ^ c[1]};
}
array<int, 3> prefCnt(int k, ll len) {
if (len <= 0) return {0, 0, 0};
ll period = 1LL << (k + 1);
if (len >= period) return {1, 1, 0};
if (k == 0) return {1, 0, 0};
ll half = 1LL << k;
if (len <= half) return mapA(prefCnt(k - 1, len));
array<int, 3> res = {1, 1, 0};
array<int, 3> add = mapB(prefCnt(k - 1, len - half));
for (int i = 0; i < 3; i++) res[i] ^= add[i];
return res;
}
int prefixWordXor(int k, ll len) {
if (len <= 0) return 0;
ll period = 1LL << (k + 1);
int ans = (len / period) & 1LL;
ll rem = len % period;
auto c = prefCnt(k, rem);
if (c[1]) ans ^= 1;
if (c[2]) ans ^= 2;
return ans;
}
int grundyValue(int k, ll s) {
int v = s & 1LL;
for (int i = 1; i <= k; i++) {
if ((s >> i) & 1LL) {
v = (v == 2 ? 1 : 2);
} else {
v = (v == 0 ? 1 : 0);
}
}
return v;
}
int prefixGameXor(ll d, ll T) {
if (T < 0) return 0;
int k = __builtin_ctzll((unsigned long long)d);
ll odd = d >> k;
ll s = T / odd;
ll rem = T % odd;
int ans = prefixWordXor(k, s);
if ((rem + 1) & 1LL) ans ^= grundyValue(k, s);
return ans;
}
int main() {
setIO();
int tc;
cin >> tc;
while (tc--) {
int n;
cin >> n;
int xr = 0;
while (n--) {
ll a, b, c, l, r;
cin >> a >> b >> c >> l >> r;
ll d = b - a;
xr ^= prefixGameXor(d, r - c);
xr ^= prefixGameXor(d, l - c - 1);
}
cout << (xr ? "Bug" : "Feature") << '\n';
}
}