Christine-'s blog

By Christine-, history, 3 months ago, In English
— You know what they call an International Grandmaster in 2026?
— They don't call it an International Grandmaster?
— No, man, they got the AI there, they wouldn't know what International Grandmaster is.
— What'd they call it?
— They call it International Master.

Introduction

There was a heated discussion recently, and I decided to quantify the rating deflation over the recent 1.5 years.

After accounting for natural improvement, I found roughly 150-190 rating points of deflation. The following is the rating gap between AI period and pre-AI period.

Codeforces rating deflation

Background

  • We need to estimate the recent rating dynamics and compare it with pre-AI dynamics.
  • Participants have natural improvement when they train, especially lower rated participants. We need to account for that.
  • We need to somehow restrict the data to likely legitimate users.

Methods

I estimated rating dynamics in two periods:

  1. January 2025 — June 2026. I call it the AI period.
  2. January 2023 — June 2024. I call it the pre-AI period.

For each period I formed 4 cohorts, based on the contestant rating at the start of the period:

  1. rating $$$\ge 2400$$$
  2. rating $$$[2100, 2400)$$$
  3. rating $$$[1900, 2100)$$$
  4. rating $$$[1600, 1900)$$$

I used several simple filtering criteria to increase the probability of legitimacy of sampled contestants. For example, I excluded several regions from sampling.

For each cohort I used all users left after filtering.

For each user, I computed delta as rating at the end of the period minus rating at the start of the period. For each cohort, I computed mean delta and median delta. The gap is AI period delta minus pre-AI period delta. The mean-gap CI is a Welch two-sample 95% confidence interval. The median-gap CI is a 95% bootstrap interval.

Results

The main tables compare raw rating change in the AI period with raw rating change in the pre-AI period.

Cohort by starting rating AI period cohort size Pre-AI period cohort size AI period mean delta Pre-AI period mean delta Mean gap Welch 95% CI
$$$\ge$$$ 2400 94 97 -164 +25 -189 [-236, -142]
$$$[2100, 2400)$$$ 117 113 -96 +84 -180 [-233, -127]
$$$[1900, 2100)$$$ 126 94 -33 +113 -146 [-199, -94]
$$$[1600, 1900)$$$ 258 203 +37 +200 -163 [-202, -124]
Cohort by starting rating AI period cohort size Pre-AI period cohort size AI period median delta Pre-AI period median delta Median gap Bootstrap 95% CI
$$$\ge$$$ 2400 94 97 -172 +17 -189 [-254, -136]
$$$[2100, 2400)$$$ 117 113 -82 +81 -163 [-236, -109]
$$$[1900, 2100)$$$ 126 94 -40 +127 -167 [-235, -103]
$$$[1600, 1900)$$$ 258 203 +18 +182 -164 [-214, -118]

So the pre-AI period had clear natural improvement in the lower three cohorts. In the AI period this improvement disappeared, and the high-rated cohorts lost rating on average.

Sample tables for rating >= 2400
Sample tables for rating [2100, 2400)
Sample tables for rating [1900, 2100)
Sample tables for rating [1600, 1900)

Limitations

  • I didn't check all the sampled users manually, so there could be cheaters among them. That would make the results underestimated.
  • Learning is becoming more effective over time, especially with AI tools. That also makes the results likely underestimated.

Conclusion

The rating deflation for legitimate participants is around 150-190 rating points. But it seems it only gets worse.


P.S. I can't miss an opportunity and mention that I am building Codeforces Community Rating, which uses peer reviews to create a list of users who are more likely to respect sportsmanship. You can join too and help with the reviews.

Full text and comments »

  • Vote: I like it
  • +202
  • Vote: I do not like it

By Christine-, 3 months ago, In English

Backstory

I have been adding hundreds of people to my Codeforces friend list so I could measure my performance against local standings I trusted more.

At the end of April 2026, I returned to Codeforces rounds after a break I had to take from the end of October 2025. It felt like one of those zombie-apocalypse movies or shows where the main character wakes up in a hospital and finds empty streets full of wreckage and zombies crawling around. Yes, you know what I mean.

In one Div. 2 round I joined virtually in May, the whole first page was filled with them. And those were only the conservatively detected zombies. One can only wonder how many seemingly healthy participants on the first page were bitten, and how many hid the bites and scratches.

Codeforces Community Rating

If the zombie story does not convince you, I humbly suggest taking a look at my rating deflation research. Right now, there is 150-190 deflation on average.

Hereby, I invite unbitten survivors to my shelter, which I call Codeforces Community Rating.

The gist of the project is a community review system focused on building a whitelist rather than a blacklist. My assumption is that a whitelist can be more effective than a blacklist because making a new Codeforces account is very easy.

What it does

  • It is a separate public ranking for users who passed community review.
  • You can apply, nominate, or report suspected unfair play. Each case is assigned to several reviewers, who independently review the case.
  • You can become a reviewer and review your peers and help build the list of legit contestants. Currently reviewer capacity is very scarce, so if you are interested in the project, consider becoming a reviewer to review cases. DM me to start.

Advantages

  • Detailed evidence is reviewed privately instead of being posted as a public guide for people trying not to get caught.
  • Cleared users appear on the community rating leaderboard. Contest standings can then be filtered to those users, so we can assess our performance more accurately.

Here are the Codeforces Round 1106 (Div. 2) community standings. The top 10 looks so much cleaner than the official board.

IzhitskiyTimofey had been donating rating for several rounds to set up a big Div. 2 jump, then still got robbed of the official win by known cheater zddtuus.

Compare that to the official standings, where 6-7 of the top 10 are likely cheaters.

Here is a reviewer POV

Eligibility
Decision rules
Review principles

Current Status

  • The project is in alpha, so expect rough edges and policy adjustments.
  • For now, community-filtered standings are available only on the project site. I plan to ship a Codeforces extension later.
  • You are welcome to report bugs and suggest ideas.

UPD 1

  • I'm working on community Elo system, so that we can have not only clearer standings but also the rating. It turned out to be trickier than I thought.
  • I'm working on a scoring algorithm. It will score legitimacy of participants, and will potentially automate most of the reviewing work.

UPD 2

  • Added an activity leaderboard visible to community memebers at Community page

FAQ

Q: I cheated in the past but I don't cheat anymore. Can I join?
A: At this stage of Community Rating, participants who cheated in the past, but supposedly haven't been cheating for a long time since then, can't join.

Q: How do you know that there are no cheaters among currently cleared participants?
A: I don't know. clear status means that a participant is likely legitimate by a significant margin. Sometimes new evidence appears and the status changes from clear to cheater. The value of the list of clear users is that the ratio of cheaters is much smaller than in the official rating.

Q: Can't we just use the friend list as this blog suggests? Why do we need the project?
A: You can use the friend list. However, the project pushes the idea further. You can think of it as a filtered union of friend lists. Moreover, the more legitimate participants are in the list, the better you can estimate your performance. Also, standings alone are less precise estimate of the progress than an Elo system, which I'm working on currently.

Q: Can I report cheaters? Say, LLI_E_P_JI_O_K apparently cheated as noted in [this blog].(https://codeforces.me/blog/entry/155842)
A: Yes, you are encouraged to report high profile cheaters. Also, note how the author of the blog is not a low-rated participant in contrast to what certain people, especially cheaters, were trying to convince everyone that only lower rated participants care about cheating and "waste" time raising legitimate concerns.

Acknowledgements

Thanks to fisher199 and HelloFromMars for active testing, good questions, and ideas, and nik_exists for suggesting OAuth.

Thanks to 123gjweq2, Nyemot, MinValgen, DarkTemplarDrop, and stefdasca for testing.

Thanks to christopherbitti9 and CatalanConvolution for questions, and to TwentyOneHundredOrBust for saying good morning in the middle of the night.

Thanks to macaquedev for the database.

Full text and comments »

  • Vote: I like it
  • +86
  • Vote: I do not like it

By Christine-, history, 4 months ago, In English
  • Vote: I like it
  • +23
  • Vote: I do not like it

By Christine-, history, 13 months ago, In English

"Lies, damned lies, and statistics."

Big shoutout to macaquedev and all the people working on the cheater database. Their project has already identified 2,100+ verified cheaters. In my experience, they don't assign a cheater mark easily; some of my reports (which, to me, were clear cases of cheating) were rejected.

Here is a small survey on cheating statistics on Codeforces. I computed the rating distribution of caught cheaters and looked at some funny demographics. Namely, we try to compare the frequency of cheating per country.

Data

The list of handles of cheaters was taken from the macaquedev GitHub. My small research is based mostly on this list. I used the Codeforces API to gather the rating and the corresponding country of each handle from the list.

Next, I used the Codeforces API to gather the number of active users (rated a contest in the last 6 months) per country.

Rating distribution of caught cheaters

The following graph is a little tricky. We should take into account that relatively higher-rated cheaters tend to cheat more cleverly. That is probably one of the reasons why there aren’t as many cheaters in the blue range as one might expect.

Rating distribution of cheaters

Here is a more detailed table with the percentages

range count in range, % upper_tail, %
≤1199 715 34.52 100
1200–1399 414 19.99 65.48
1400–1599 434 20.96 45.49
1600–1899 398 19.22 24.53
1900–2099 61 2.95 5.31
2100–2399 39 1.88 2.37
≥2400 10 0.48 0.48

Grey cheaters are the ones caught most often. We can probably also assume that they are the easiest to catch. My subjective feeling is that the situation is grimmer in blue/purple than the graph suggests.

Also, note the blue peak in the 1600–1700 range. Those are probably people who cheated their way to reach blue for some sort of placement and then dropped CP (thank God).

Demographics of caught cheaters

Since many people don't list their country on CF, in this section I only take into account users with listed countries. Sadly, we lose more than half of the data here.

I was not satisfied with claims that we see cheaters from region X more often than from other regions simply because there are a lot of participants from region X. To me, this statement is too loose.

How about applying Bayes’ formula? How about computing the conditional probability

Unable to parse markup [type=CF_MATHJAX]

, which we will denote for brevity as

Unable to parse markup [type=CF_MATHJAX]

?

Let’s make a simple computation:

Unable to parse markup [type=CF_MATHJAX]

Here is the problem: I don’t know how to estimate

Unable to parse markup [type=CF_MATHJAX]

. Of course, there are many more cheaters than the 2100 listed in the database. So, instead, for each country X we compute the ratio

Unable to parse markup [type=CF_MATHJAX]

Then

Unable to parse markup [type=CF_MATHJAX]

cancels out and we have

Unable to parse markup [type=CF_MATHJAX]

As the author of this blog, I choose Russia as the reference country.

Thus, for each country X we need to estimate probabilities

Unable to parse markup [type=CF_MATHJAX]

and

Unable to parse markup [type=CF_MATHJAX]

.
  • cheaters — % of all identified cheaters who are from the country. It estimates

    Unable to parse markup [type=CF_MATHJAX]

    and is computed as

    Unable to parse markup [type=CF_MATHJAX]

    .
  • users — % of all identified users who are from the country. It estimates

    Unable to parse markup [type=CF_MATHJAX]

    and is computed as

    Unable to parse markup [type=CF_MATHJAX]

  • rate

    Unable to parse markup [type=CF_MATHJAX]

    .

Now we can observe the computed values. I dropped countries with less than 5 cheaters caught, so that our inference is more stable.

country cheaters count cheaters, % users, % rate
India 530 61.92 45.02 4.0921
Vietnam 46 5.37 3.44 4.6476
Bangladesh 34 3.97 11.19 1.0557
Egypt 32 3.74 7.02 1.5837
China 31 3.62 9.69 1.1115
Pakistan 27 3.15 0.58 16.0755
United States 13 1.52 1.48 3.0494
Russia 13 1.52 4.52 1
Iran 10 1.17 1.04 3.3395
Palestinian Territory 8 0.93 0.94 2.9611
Azerbaijan 8 0.93 0.34 8.1122
Japan 8 0.93 0.75 3.6908
South Korea 6 0.7 0.76 2.7551
Brazil 5 0.58 1.13 1.5379
Kazakhstan 5 0.58 1.18 1.4683
Romania 5 0.58 0.56 3.1301

Here is a visualization with the rate sorted in descending order.

Rate

Limitations

I am not biased at all, and I didn’t expect such results. However, keep in mind that the sample size is still not very large (except for India), so the inference can be noisy. Also, note that I don’t build confidence intervals, so the differences between some pairs of countries may not be statistically significant.

For the rating distribution of cheaters, I've already noted that it naturally doesn't give a precise reflection of the reality because it is more complex to catch smart cheaters.

Conclusions

We provided a rough estimate of the factors by which the rate of cheating differs by country and debunked claims like 'they cheat a lot because there are just a lot of them'. Some are caught cheating an order of magnitude more often than others. To make the estimates and the statistics in blue/purple range more precise, please, report more cheaters.

Full text and comments »

  • Vote: I like it
  • +290
  • Vote: I do not like it

By Christine-, history, 20 months ago, In English

Introduction

Hello, Codeforces!

I want to share my suspicions about harsh__h.

I wouldn't write the blog if he was not a relatively high ranked individual who both participated in problem setting and testing. Yesterday, I accidentally noted that the 6th place (standings), in Codeforces Round 1002 (Div. 2), which turned to be harsh__h, had very suspicious submissions. Next, I will try to explain in detail what got my attention in the order in which I uncovered it.

Part 1. Codeforces Round 1002 Div2.

During the contest in problems A(304070640), B(304090034), C(304111128) harsh__h doesn't use spaces between brackets. That is, he writes, say, for(ll i=0;i<n;i++){ not for (ll i = 0; i < n; i++) {. Also, for the newline he uses endl cout << mex << endl;, and these are not interactive problems.

Next, In problems D (304092485), E(304129652), in which I think he used chatgpt, harsh__h uses spaces between brackets and keywords, for example, writing for (ll i = 0; i < n; i++) { instead of for(ll i=0;i<n;i++){. Here for the newline he uses ‘\n', cout << (ans == inf ? -1 : ans) << '\n';

In addition, compare how he read the graph just a week ago in another graph task 303111414. A week ago it was

for(ll i=0;i<n-1;i++){
    ll x,y;cin>>x>>y;
    x--;
    y--;
    adj[x].push_back(y);
    adj[y].push_back(x);
}

and yesterday it was

for (ll i = 0; i < m1; i++) {
     ll a, b;
     cin >> a >> b;
     --a;
     --b;
     g1[a].push_back(b);
     g1[b].push_back(a);
     e1.push_back({a, b});
}

Note also, that in 304129652 he doesn’t use spaces even in cin/cout. cout<<ans<<endl;

To sum up, the submissions look like they were written by different people.

After the contest I noted the unusual codestyle and here was his reaction

So he didn’t comment on the code style, instead he argued that he solved E1, E2, and that he, Codeforces master, doesn’t know if ChatGPT can solve a very straightforward 2059D - Graph and Graph.

Then, there was this guy MayankBhakat, probably his friend, who tried very hard to defend harsh__h, trying to ignore very suspicious codestyle.

Part 2. Educational Codeforces Round 173.

First, at this point harsh__h is a master, so Educational Codeforces Round 173 (Rated for Div. 2) is unrated for him. In this round harsh__h made submissions in very short intervals.

Let’s break it down.

2043A - Coin Transformation. In this submission 298252659 he doesn’t use his template. Also, it is very unusual when a codeforces master writes 50 lines of code to fail to solve Div2A. Then goes this submission 298254253. Now it is AC, and apparently, and someone left some comments).

Then, just 1 minute after he is done with A, he sends D 298254978, where he also does not use the template.

Then, 1 minute after the last D submission, he sends E 298257018 with the same code style as in A, D, which differs significantly from his usual style.

Then, 1 minute after the last E submission, he sends F, etc. So the submission history looks like this

I think that I made my point.

Part 3. Codeforces Round 956 (Div. 2) and ByteRace 2024 (UPD.1)

So, I decided to look into his older submissions. For example, Codeforces Round 956 (Div. 2) and ByteRace 2024.

Consider this submission 269285676 of 1983F - array-value. The codestyle

    while (lo < hi) {
        ll mid = (lo+hi)/2;
        if (slv(mid) >= k) hi = mid;
        else lo = mid+1;
    }
    
    cout << hi << '\n';

While another problem 1983E - I Love Balls in the very same contest 269275920

    if(bb%2==0){
        alice+=(((sum2*(bb))%M)*mod_inv(2,M))%M;
    }else{
        alice+=(((sum2*(bb+1))%M)*mod_inv(2,M))%M;
    }
    alice%=M;
    ll bob = sum*aa+sum2*bb-alice;
    bob%=M;
    bob+=M;
    bob%=M;
    cout<<alice<<" "<<bob<<endl;

Next, look at problem 1983D - Swap Dilemma, submission 269243749, where he doesn't use ll in count_inversion

    ll n;cin>>n;
    vector<int> a(n);
    cin>>a;
    vector<int> b(n);
    cin>>b;
    auto count_inversion=[&](vector<int> arr)->long long{
     
            int n = (int)arr.size();
     
            vector<int> buffer(n);
     
            function<long long(int,int,int,int)> combine=[&](int left_l,int left_r,int right_l,int right_r)->long long{
                int r_pointer=left_r;
                long long cnt=0;
            ...

In addition, check the comments for additional suspicios cases. So harsh__h has a quite long history of making very suspicious submissions. His results in these contests should be investigated, in my opinion.

Plagiarism detection complaint (UPD.2)

Yesterday harsh__h and MayankBhakat were very vocal about me providing any proofs. Sadly, today there are no comments from these guys when I listed a lot of suspicious code.

Also, it is quite interesting that MayankBhakat complains in his blog about him being flagged by the plag system. So now it is less surprising why he defended harsh__h.

Questions left unanswered (UPD.3)

Unfortunately, two days later, despite huge interest from the community, there is still no reaction from harsh__h and he has chosen to ignore everything waiting for the attention to the case to fade. This fact only makes the actions of harsh__h even more suspicious. MikeMirzayanov

Conclusion

Could you please MikeMirzayanov, Vladosiya, KAN check the submissions? harsh__h participated in problem setting and in testing in the past. I believe that this case should be investigated to keep the integrity and fairness of the future rounds. I really hope that harsh__h just has a very peculiar codestyle. Unfortunately, I am not sure at all that this is the case.

Also, I tried my best to not make any accusations but unfortunately the reaction of harsh__h MayankBhakat made me too emotional in my comments. For that I am deeply sorry.

Full text and comments »

  • Vote: I like it
  • +241
  • Vote: I do not like it