wangmarui's blog

By wangmarui, history, 9 months ago, In English

We'd like to thank you all for participating in the contest, and hope you enjoyed it. Any feedback would be appreciated!

Rate The Contest!

2183A — Binary Array Game

Idea & Preparation: wangmarui

Rate The Problem!
Hint 1
Hint 2
Solution
Implementation

2183B — Yet Another MEX Problem

Idea & Preparation: wangmarui

Rate The Problem!
Hint 1
Hint 2
Solution
Implementation

2183C — War Strategy

Idea & Preparation: Network_Error

Rate The Problem!
Hint 1
Hint 2
Hint 3
Claim 1
Proof
Claim 2
Proof
Solution
Implementation
Bonus

2183D1 — Tree Coloring (Easy Version)

Idea & Preparation: jiazhichen844

Rate The Problem!
Hint 1
Hint 2
Solution

2183D2 — Tree Coloring (Hard Version)

Idea & Preparation: jiazhichen844

Rate The Problem!
Hint 3
Solution 1
Solution 2
Implementation (Solution 1)

2183E — LCM is Legendary Counting Master

Idea & Preparation: Gold14526

Rate The Problem!
Hint 1
Hint 2
Hint 3
Hint 4
Solution
Implementation

2183F — Jumping Man

Idea & Preparation: Neil_Qian

Rate The Problem!
Hint 1
Hint 2
Hint 3
Hint 4
Solution
Implementation

2183G — Snake Instructions

Idea & Preparation: xvchongyv & wangmarui

Rate The Problem!
Hint 1
Hint 2
Hint 3
Hint 4
Solution
Implementation

2183H — Minimise Cost

Idea & Preparation: Hoks_ Special Thanks: Sorasaki_Hina

Rate The Problem!
Hint 1
Hint 2
Hint 3
Hint 4
Solution
Implementation

2183I1 — Pairs Flipping (Easy Version)

Idea & Preparation: Network_Error Special Thanks: N_z__

  • Good Problem
  • Okay Problem
  • Bad Problem
  • Didn't Solve

What if $$$s=1111\ldots$$$?

Try dividing the sequence into two equal halves, eliminating both halves by assigning odd and even lengths respectively.

Try processing recursively to reduce $$$n$$$ to a smaller scale.

Try further optimizing one of the two halves.

If $$$n$$$ is even, we only consider $$$s_1s_2\ldots s_{n-1}$$$. Now assume that $$$n$$$ is odd. Let $$$m=\frac{n-1}2$$$.

Consider dividing the $$$n$$$ numbers into the first $$$m$$$ and the last $$$m+1$$$ parts. The first $$$m$$$ are eliminated using odd lengths in $$$[1,m-1]$$$, and the last $$$m+1$$$ are eliminated using even lengths in $$$[1,m]$$$. (Assume that $$$m$$$ is even; it is similar when $$$m$$$ is odd.)

Let $$$solvePartially(l,r,p)$$$ denote the process of considering that there are 1s only in the interval $$$[l,r]$$$ and at some position $$$p$$$ outside $$$[l,r]$$$, and only using lengths in $$$[1,r-l]$$$ to eliminate. If $$$s_l=s_r=0$$$ or $$$s_l=s_r=1$$$, we operate on $$$l,r$$$ and recurse to $$$solvePartially(l+1,r-1,p)$$$; otherwise, assume that $$$s_l=1,s_r=0$$$ and $$$r \lt p$$$. If $$$p-(r-l)\in [l+1,r-1]$$$, we operate on $$$p-(r-l),p$$$ and then recurse to $$$solvePartially(l+1,r-1,l)$$$. Otherwise, the $$$1$$$ at $$$p$$$ is difficult to eliminate. Note that this situation occurs at most $$$\left\lfloor\log_3\frac{n}2\right\rfloor$$$ times, so we have obtained a solution with $$$c\le 2\left\lfloor\log_3\frac{n}2\right\rfloor+2$$$, roughly $$$24$$$ in the constraints of the problem, which is not acceptable.

Proof that the above situation occurs at most $$$\left\lfloor\log_3\frac{n}2\right\rfloor$$$ times:

  • Note that the occurrence of an impossible elimination necessarily comes with $$$p-(r-l)\ge r$$$. Let $$$q+p=l+r$$$; then we must have $$$3(r-l)\le p-q$$$. Since $$$1\le r-l\le \frac{n}2$$$, it can happen at most $$$\left\lfloor\log_3\frac{n}2\right\rfloor$$$ times. In other words, each time an elimination is impossible, the interval length must reduce to $$$1/3$$$ of its original length.

In the above approach, the left and right sides are almost independent. Since operations on the left side are allowed to extend to the right side, we try to eliminate the left side completely. Let $$$solveCompletely(l,r,p)$$$ denote that the interval $$$[l,r]$$$ except for some position $$$p$$$ on the left side has been completely eliminated, and that we still need to eliminate position $$$p$$$ together with parts outside $$$[l,r]$$$. If $$$s_l=s_r=1$$$ or $$$s_l=s_r=0$$$, we eliminate $$$l,r$$$ and recurse to $$$solveCompletely(l-1,r+1,p)$$$; otherwise, assume that $$$s_l=1,s_r=0$$$, we eliminate $$$p,p+r-l$$$ and then recurse to $$$solveCompletely(l-1,r+1,l)$$$. In this way, for the left half, we can reduce it to a single remaining position $$$p$$$. Finally, we have optimised to $$$c\le \left\lfloor\log_3 \frac n2\right\rfloor+2$$$, which is below $$$14$$$ under the constraints of this problem. The code is easy to implement.

#include <bits/stdc++.h>
using namespace std;
signed main() {
    ios_base::sync_with_stdio(false); 
    cin.tie(0);
    int t;
    cin >> t;
    while(t--) {
        int n;
        cin >> n;
        string a;
        cin >> a;
        vector<int> ops(n/2+5);
        auto operate = [&](int i)->void{
            if(ops[i]==0) return;
            else {
                a[ops[i]-1]^=1;
                a[ops[i]-1+i]^=1;
            }
        };  
        auto solveCompletely = [&](auto self, int l, int r, int x)->void{
            if(l>r) return;
            if(a[l]==a[r]) {
                if(a[l]=='1') ops[r-l]=l+1, operate(r-l);
                self(self, l+1, r-1, x);
                return;
            }
            if(x!=-1 && x<l) {
                if(x+r-l>=l) {
                    ops[r-l]=x+1, operate(r-l);
                }
            } else if(x!=-1 && x>r) {
                if(x-r+l<=r) {
                    ops[r-l]=x-r+l+1, operate(r-l);
                }
            }
            if(a[l]=='1') {
                self(self, l+1, r-1, l);
            } else {
                self(self, l+1, r-1, r);
            }
        };
        auto solvePartially = [&](auto self, int l, int r)->int{
            if(l>r) return -1;
            if(l==r) if(a[l]=='1') return l; else return -1;
            int x = self(self, l+1, r-1);
            if(a[l]==a[r]) {
                if(a[l]=='1') ops[r-l]=l+1, operate(r-l);
                return x;
            } else {
                if(x!=-1) {
                    ops[r-l]=x+1, operate(r-l);
                }
                if(a[l]=='1') return l;
                else return r;
            }
        };
        solvePartially(solvePartially, 0, (n-1)/2-1);
        if(n%2) solveCompletely(solveCompletely, (n-1)/2, n-1, -1);
        else solveCompletely(solveCompletely, (n-1)/2, n-2, -1);
        for(int i=1; i<=n/2; i++) cout << ops[i] << " ";
        cout << endl;
    }
    return 0;
}

2183I2 — Pairs Flipping (Hard Version)

Idea & Preparation: Network_Error

  • Good Problem
  • Okay Problem
  • Bad Problem
  • Didn't Solve

In the I1 approach, we can observe that the main cost arises from isolated $$$1$$$'s outside the interval that occasionally cannot be eliminated. We consider optimizing this situation.

The following diagram illustrates a scenario where such an elimination fails:

 1111111111111|1??????0|1111111111110
 p             l      r             q

Here, $$$p$$$ is the previous $$$1$$$ we could not eliminate (without loss of generality, assume $$$p \lt l$$$), the current interval being processed is $$$[l,r]$$$, and $$$l-p \ge r-l$$$ (making it impossible to eliminate directly using the previous method). $$$q$$$ is the symmetric point of $$$p$$$.

At this point, the operation lengths we can use are $$$q-p-2, q-p-4, q-p-6, \ldots, r-l$$$. Note that $$$q-p$$$ is excluded because we have already used it earlier.

Let the lengths of the three segments be $$$A$$$, $$$B$$$, and $$$C$$$, where $$$A=C$$$. This scenario is denoted as $$$F(A,B,C)$$$.

Next, we will study in detail how to eliminate for $$$F(A,B,C)$$$.

If $$$A \lt B-1$$$, we have essentially solved it in I1.

For example, in a simple case where $$$r-l = l-p$$$ and $$$s_l=1, s_r=0$$$, we can apply an operation of length $$$r-l$$$ on $$$p$$$ and $$$l$$$, thereby eliminating both $$$p$$$ and $$$l$$$ simultaneously.

For other cases, we can show that there is always a method to eliminate until only one $$$1$$$ remains, and this remaining $$$1$$$ can only be at one of the positions $$$l, l-1, l-2, r, r+1, r+2$$$. This part can be resolved through case analysis.

Specifically, we only need to consider three cases: $$$A=B$$$, $$$A=B+1$$$, or $$$A=B-1$$$. If the case falls outside these three, such as $$$A',B',C'$$$, we always shift the interval inward and transform it into $$$A'-1, B'+2, C'-1$$$.

We take $$$F(B-1,B,B-1)$$$ as an example to discuss the specific method.

We further discuss based on $$$s_l$$$ and $$$s_r$$$. For convenience, we label the positions starting from $$$p$$$ as $$$0, \ldots, q-p$$$, and use a sequence to represent the positions operated on in order of decreasing length. Let the maximum available length be $$$L = q-p-2$$$. For example, the sequence $$$0,3,1$$$ means we first use an operation of length $$$L$$$ on $$$p$$$ and $$$p+L$$$, then use an operation of length $$$L-2$$$ on $$$p+3$$$ and $$$p+3+(L-2)$$$, and finally use an operation of length $$$L-4$$$ on $$$p+1$$$ and $$$p+1+(L-4)$$$.

  1. $$$s_l = s_r = 0$$$. We operate in order: $$$[0,1,2,\ldots,B-4], 2B-5, B-3$$$. Finally, a $$$1$$$ remains at index $$$B-2$$$.
  2. $$$s_l = 1, s_r = 0$$$. We operate in order: $$$0, [(3,2),(5,4),(7,6),\ldots,(B-3,B-4)], B-1, 1$$$. Finally, a $$$1$$$ remains at index $$$B-2$$$.
  3. $$$s_l = 0, s_r = 1$$$. We operate in order: $$$[0,1,2,\ldots,B-3], 2B-3$$$. Finally, a $$$1$$$ remains at index $$$B-2$$$.
  4. $$$s_l = s_r = 1$$$. We operate in order: $$$[1,2,3,\ldots,B-2], 0$$$. Finally, a $$$1$$$ remains at index $$$2B-2$$$.

Similarly, elimination methods for $$$F(B,B,B)$$$ and $$$F(B+1,B,B+1)$$$ can be obtained.

Thus, between every two adjacent $$$1$$$'s that cannot be eliminated, we can always save one elimination, leaving a $$$1$$$ within a distance of at most $$$2$$$ from $$$l$$$ or $$$r$$$. Let the interval length be $$$s$$$. Whenever a $$$1$$$ cannot be eliminated, $$$s$$$ becomes at least $$$\frac19 s + \frac{2}{3}$$$. Therefore, the number of remaining $$$1$$$'s is approximately $$$\log_9\frac{n}{2}+O(1)$$$. Note that when the interval length is small, it may consume many $$$1$$$'s. A constant optimization is that when the recursion interval length does not exceed $$$18$$$, we can use an $$$O(n^2 2^n)$$$ dynamic programming approach to easily find the optimal solution, and the optimal solution can always leave no more than $$$1$$$ remaining $$$1$$$. Additionally, there are other optimizations, such as running the algorithm forward and backward on the sequence and taking the better result. All of these can pass.

It can be proven that when $$$n \le 2 \times 10^6$$$, the total number of $$$1$$$'s does not exceed $$$7$$$.

#include<bits/stdc++.h>
using namespace std;

const int N=2e6,DB=20;
int n,a[N+1];
int ans[N+1];
int mid;
inline void op(int x,int y)
{
    if(x>y)swap(x,y);
    ans[y-x]=x;
    a[x]^=1;
    a[y]^=1;
}
inline void del(int x,int y)
{
    if(x>y)swap(x,y);
    if(!ans[y-x])return;
    ans[y-x]=0;
    a[x]^=1;
    a[y]^=1;
}
#define ppc __builtin_popcount
namespace DP{
    int n;
    bool f[DB+1][1<<DB+1];
    int g[DB+1][1<<DB+1];
    void dp()
    {
        n=DB;
        f[n][0]=1;
        for(int S=1;S<(1<<n);S<<=1)f[n][S]=1;
        for(int len=n;len>=2;len-=2)
        {
            for(int S=0;S<(1<<n);S++)
            {
                if(!f[len][S])continue;
                f[len-2][S]=1;
                g[len-2][S]=-1;
                for(int i=0;i+len-1<n;i++)
                {
                    f[len-2][S^(1<<i)^(1<<(i+len-1))]=1;
                    g[len-2][S^(1<<i)^(1<<(i+len-1))]=i;
                }
            }
        }
    }
    vector<int>ask(int S)
    {
        int len=0;
        vector<int>ans(n+2);
        while(len<n)
        {
            int pos=g[len][S];
            ans[len+1]=pos;
            if(pos!=-1)
            {
                S^=1<<pos;
                S^=1<<(pos+len+1);
            }
            len+=2;
        }
        return ans;
    }
}
int solvec(int l,int r,int p)
{
    if(!l)return p;
    if(a[l]==a[r])
    {
        if(a[l])op(l,r);
        return solvec(l-1,r+1,p);
    }
    if(p)op(p,p+r-l);
    if(a[l])return solvec(l-1,r+1,l);
    else return solvec(l-1,r+1,r);
}
void solvep(int l,int r,int p,bool flag)
{
    if(l>=r)return;
    if(!p)
    {
        if(a[l]==a[r])
        {
            if(a[l])op(l,r);
            solvep(l+1,r-1,0,0);
            return;
        }
        if(a[l])solvep(l+1,r-1,l,0);
        else solvep(l+1,r-1,r,0);
        return;
    }
    if(r-l+1==DB)
    {
        int S=0;
        for(int i=l;i<=r;++i)S|=a[i]<<(i-l);
        vector<int>res=DP::ask(S);
        for(int len=r-l;len>=1;len-=2)
        {
            if(res[len]!=-1)op(res[len]+l,res[len]+len+l);
        }
        return;
    }
    int x=l+r-p,y=p;
    if(x>y)swap(x,y);
    int A=l-x,B=r-l+1;
    int len=y-x-2;
    auto f=[&](int a){int b=a+len;len-=2,a=a+x,b=b+x;if(p>l)a=l+r-a,b=l+r-b;op(a,b);};
    if(!flag&&r-l+1>=10&&abs(A-B)==1)
    {
        for(int i=x+1;i<l;++i)del(i,l+r-i);
        int type=a[l]|(a[r]<<1);
        if(p>r)type=a[r]|(a[l]<<1);
        if(A==B-1)
        {
            switch(type)
            {
                case 0:for(int i=0;i<=B-4;i++)f(i);f(2*B-5);f(B-3);break;
                case 1:f(0);for(int i=3;i<=B-3;i+=2)f(i),f(i-1);f(B-1);f(1);break;
                case 2:for(int i=0;i<=B-3;i++)f(i);f(2*B-3);break;
                case 3:for(int i=1;i<=B-2;i++)f(i);f(0);break;
            }
        }
        else if(A==B)
        {
            switch(type)
            {
                case 0:for(int i=0;i<=B-2;i++)f(i);f(2*B-1);break;
                case 1:
                    if(B%3==2){f(1);f(0);for(int i=3;i<=B-5;i+=3)f(i+1),f(i+2),f(i);f(B-1);f(B);f(2);}
                    else if(B%3==0){f(1);f(0);for(int i=3;i<=B-6;i+=3)f(i+1),f(i+2),f(i);f(B-3);f(B);f(B-1);f(2);}
                    else{f(1);f(0);for(int i=3;i<=B-7;i+=3)f(i+1),f(i+2),f(i);f(B-3);f(B-4);f(B);f(B-1);f(2);}
                    break;
                case 2:f(1);f(0);for(int i=3;i<=B-3;i+=2)f(i),f(i-1);f(B-1);f(2*B-2);break;
                case 3:f(0);for(int i=3;i<=B-1;i+=2)f(i),f(i-1);f(1);break;
            }
        }
        else if(A==B+1)
        {
            switch(type)
            {
                case 0:for(int i=1;i<=B;i++)f(i);f(0);break;
                case 1:for(int i=1;i<B;i++)f(i);f(0);f(B);break;
                case 2:for(int i=1;i<=B-1;i+=2)f(i),f(i-1);f(2*B);break;
                case 3:
                    if(B%3==2){f(0);f(1);for(int i=3;i<=B-2;i+=3)f(i+2),f(i),f(i+1);f(2);}
                    else if(B%3==0){f(1);f(0);for(int i=3;i<=B-3;i+=3)f(i+1),f(i+2),f(i);f(B);f(2);}
                    else{f(1);f(0);for(int i=4;i<=B-3;i+=3)f(i),f(i+1),f(i-1);f(B);f(B-1);f(2);}
                    break;
            }
        }
        for(int i=x;i<=l;++i)if(a[i]){solvep(l+1,r-1,i,1);return;}
        for(int i=r;i<=y;++i)if(a[i]){solvep(l+1,r-1,i,1);return;}
        solvep(l+1,r-1,0,1);
        return;
    }
    if(a[l]&&a[r])
    {
        op(l,r);
        solvep(l+1,r-1,p,flag);
        return;
    }
    len=r-l;
    auto down=[&](){
        if(a[l])solvep(l+1,r-1,l,0);
        else if(a[r])solvep(l+1,r-1,r,0);
        else solvep(l+1,r-1,0,0);
    };
    if(p+len>l&&p+len<r)
    {
        op(p,p+len);
        down();
        return;
    }
    if(p-len>l&&p-len<r)
    {
        op(p,p-len);
        down();
        return;
    }
    down();
}
int rn;
void solve()
{
    cin>>n;
    rn=(n>>1);
    for(int i=1;i<=n;++i)
    {
        char ch;
        cin>>ch;
        a[i]=ch-'0';
    }
    for(int i=1;i<=n;++i)ans[i]=0;
    if(!(n&1))
    {
        op(n-(n>>1),n);
        --n;
    }
    mid=(n+1>>1);
    if(!(mid&1))--mid;
    int p=solvec((mid>>1),(mid>>1)+2,(a[(mid>>1)+1]?(mid>>1)+1:0));
    solvep(mid+1,n,0,0);
    for(int i=1;i<=rn;++i)cout<<ans[i]<<' ';
    cout<<'\n';
}
int main()
{
    DP::dp();
    int T;
    cin>>T;
    while(T--)solve();
    return 0;
}

Full text and comments »

Tutorial of Hello 2026
  • Vote: I like it
  • +146
  • Vote: I do not like it

By wangmarui, history, 9 months ago, In English

Happy new year, Codeforces!

We are glad to invite you to take part in Hello 2026, which will start on Jan/07/2026 17:35 (Moscow time). You will be given 9 problems and 3 hours to solve them. At least one problem will be interactive, so please make sure to read the guide for interactive problems before the contest. This round is open and rated for everyone.

Problems are authored by wangmarui, Gold14526, Hoks_, Neil_Qian, Network_Error, jiazhichen844 and xvchongyv.

We would like to thank:

Score Distribution: $$$500 - 1000 - 1500 - (1000 - 2000) - 2250 - 2750 - 4000 - 4000 - (4500 - 1000)$$$

Good Luck & Have Fun!

Update 1: The score distribution have been changed a bit. In particular, problem I will be split into two subtasks.

Update 2: Hacks will be disabled on problems A-D.

Update 3: editorial — https://codeforces.me/blog/entry/149944

Update 4: Congratulations to the winners!

  1. maroonrk
  2. ecnerwala
  3. turmax
  4. peti1234
  5. kotatsugame
  6. hos.lyric
  7. BurnedChicken
  8. strapple
  9. stepanov.aa
  10. antontrygubO_o

Full text and comments »

Announcement of Hello 2026
  • Vote: I like it
  • +1039
  • Vote: I do not like it

By wangmarui, history, 2 years ago, In English

I can't find many nice problems, so please drop some problems even if it's naive!

Full text and comments »

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