Some time ago, plagues published The most outrageous cheating in the history of Huawei Challenge, questioning whether several highly ranked accounts in the Huawei Challenge might have collaborated with each other. The original post was written with considerable confidence in labeling those accounts as cheaters. While some of the cases it discussed may have had relatively strong supporting evidence, many of the other connections were based on weaker correlations or incidents that, as far as I know, have not been independently substantiated. This post does not attempt to evaluate or revisit those allegations.
However, that post drew my attention to this account. I noticed an unusual period in plagues's rating trajectory, so I reviewed 59 of his CONTESTANT submissions from the following six contests. There are several differences in coding style and apparent origin among these submissions that I believe deserve an explanation, and I hope plagues can respond to them specifically.
Please keep in mind:
Differences in coding style alone do not prove that plagues used AI or engaged in any other form of cheating.
Frequently changing code skeletons
I found at least the following different code skeletons in plagues's submissions.
Their main differences include whether using namespace std; is used, the form of the loop over test cases, and whether std::cin.tie(nullptr)->sync_with_stdio(false); appears.
For the purpose of this comparison, I do not distinguish between int main() and int32_t main().
Skeleton 1
int main() {
int t;
std::cin >> t;
while (t--) {
}
}
Skeleton 2
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int t;
std::cin >> t;
while (t--) {
}
}
Skeleton 3
using namespace std;
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
}
}
Skeleton 4
using namespace std;
int main() {
cin.tie(nullptr)->sync_with_stdio(false);
int t;
cin >> t;
while (t--) {
}
}
Skeleton 5
int main() {
std::cin.tie(nullptr)->sync_with_stdio(false);
int t;
std::cin >> t;
for (int i = 1; t--; ++i) {
}
}
Skeleton 6
int main() {
int t;
std::cin >> t;
for (int i = 1; t--; ++i) {
}
}
Below is a list of the skeletons used in these contests. The number in each cell denotes the skeleton used; clicking it opens the corresponding submission.
Order Capital Round 1 (Codeforces Round 1038, Div. 1 + Div. 2) — Contest 2122
| A | B | C | D |
|---|---|---|---|
| 1 | 1 | 1 | 2 |
Codeforces Round 1040 (Div. 1) — Contest 2129
| A | B | C1 | C2 | D | E |
|---|---|---|---|---|---|
| 1 | 1 | 1 | 1 | 3 | 3 |
Codeforces Round 1046 (Div. 1) — Contest 2135
| A | B | C | D1 | D2 |
|---|---|---|---|---|
| 5 | 6 | 6 | 1 | 1 |
Codeforces Global Round 29 — Contest 2147
| A | B | C | D | E | G |
|---|---|---|---|---|---|
| 4 | 4 | 4 | 4 | 4 | 4 |
Order Capital Round 2 (Codeforces Round 1104, Div. 1 + Div. 2) — Contest 2237
| A | B | C | D | E | F | G |
|---|---|---|---|---|---|---|
| 4 | 4 | 4 | 4 | 4 | 4 | communication problem |
Codeforces Round 1105 (Div. 1) — Contest 2239
| A | B | C | D |
|---|---|---|---|
| 4 | 4 | 4 | 4 |
Why did your code skeleton repeatedly switch between Skeleton 1 and other skeletons during the first three contests?
In particular, how do you explain using namespace std; repeatedly appearing and disappearing, as well as the different forms of the test-case loop?
Why, starting from Codeforces Global Round 29 (Contest 2147), did your submissions suddenly become consistently standardized on Skeleton 4? I could not find a single use of Skeleton 4 in the three contests above it.
And this transition happened in exactly the contest where you became a Grandmaster.
Is this a coincidence?
Please explain.
An unusual 2129D
plagues's submission 331847745 for 2129D differs from his other submissions in many respects.
In this submission, he uses T(expr) syntax to convert expressions to fundamental types. For example:
int m(long long x, long long y) { return int((x * y) % M); }
inline uint32_t P(uint16_t x, uint16_t y) { return (uint32_t(x) << 8) | y; }
In his other submissions, he normally uses (T)expr or (T) expr.
For example, in his 2129E submission 331855693 from the same contest, he wrote:
int Bsz = max(1, (int) sqrt(n));
The only exception I found is in his 2135C submission 336011001, where he wrote:
if (a[v] == -1) return void(a[v] = x);
In the 2129D submission, every ordinary C-style for loop uses postfix increment:
for (int i = 0; i <= n; i++)
for (int j = 1; j < i; j++)
for (int i = 1; i <= n; i++)
for (int i = 0; i <= n; i++)
for (int g = 2; g <= n + 1; g++)
for (int l = 0; l + g <= n + 1; l++)
for (int x = l + 1; x < r; x++)
There are 7 such loops.
I counted all ++ expressions in ordinary C-style for loops across his submissions from these six contests, excluding generic template libraries such as AngelBeats and BigInt.
There are 171 in total.
Of these, only 10 use postfix increment.
This single file contains 7 of those 10 postfix increments, while containing 0 of the other 161 prefix increments.
This submission also frequently uses the form for (expr1)expr2, with no space before expr2, for example:
for (int j = 1; j < i; j++)c[i][j] = a(c[i - 1][j - 1], c[i - 1][j]);
for (int i = 1; i <= n; i++)t[i] = v[i - 1];
for (int i = 0; i <= n; i++)d[i][i + 1][P(0, 0)] = 1;
if (l && r != n + 1)q = (x - l <= r - x) ? l : r;
else if (l)q = l;
else if (r != n + 1)q = r;
if (t[x] != -1 && k != t[x])continue;
if (l && t[l] != -1 && y > t[l])continue;
if (r != n + 1 && t[r] != -1 && z > t[r])continue;
for (int &x: v)cin >> x;
In his other submissions, the corresponding style is consistently for (expr1) expr2, with a space before the body.
The non-main top-level functions in this submission are:
a, m, b, P, L, R, s
I did not find this function-naming style in his other submissions.
Why is this particular submission so unusual that it differs from his other submissions in so many independent stylistic details?
Addendum: Two Different Fenwick Tree Implementations in the Same Contest
In the first version of this article, I overlooked another highly suspicious issue.
His Fenwick tree in 331780529 is written as follows:
struct BIT {
std::vector<int> t;
BIT(int n): t(n + 2) {}
void modify(int i, int x) {
for (++i; i < t.size(); i += i & -i) t[i] += x;
}
int get(int i) {
int ans = 0;
for (++i; i; i -= i & -i) ans += t[i];
return ans;
}
int get(int l, int r) {
return get(r) - get(l - 1);
}
};
However, his Fenwick tree in 331855693 is written as follows:
struct B {
static vector<int> t, z;
static int c;
int n;
B(int N = 0) : n(N + 1) {
}
static void nxt() { ++c; }
void upd(int i, int v) {
for (++i; i <= n; i += i & -i) {
if (z[i] != c) {
z[i] = c;
t[i] = 0;
}
t[i] += v;
}
}
int kth(int k) {
int i = 0;
for (int b = 1 << 18; b; b >>= 1) {
int j = i + b, v = (j <= n && z[j] == c ? t[j] : 0);
if (v < k) {
k -= v;
i = j;
}
}
return i;
}
};
vector<int> B::t(S + 3);
vector<int> B::z(S + 3);
int B::c = 0;
These two pieces of code come from the same contest.
I can understand that the two Fenwick trees have different overall designs and query interfaces because they were used for different purposes. However, please explain why BIT became B, and why void modify(int i, int x) became void upd(int i, int v).
Today, generative AI can imitate an existing coding style when prompted to do so. Therefore, stylistic characteristics of a single piece of code are difficult to treat as decisive evidence by themselves.
That is also why I am focusing on these relatively uncommon differences in style.
So please forgive me for examining your code this closely.
I am not accusing you of being a cheater.
I am only asking you to provide a specific and reasonable explanation for the observations above.












