Minimum Increasing Cycle#12253

Minimum Increasing Cycle (Editorial)

Problem Author:

Hasan Saleh (MathModel)

Prepared by:

Hasan Saleh (MathModel)

Edited by:

Hasan Saleh (MathModel)

Solution

We only care about which indices we keep (0 ops) and which we fix in one shot (1 op). One operation on a_i allows a_i\leftarrow(a_i+t)\bmod k with t\ge m, and since we can add any multiple of on top, one op can set a_i to any value in [0,k-1]. So:

  • kept index: value stays a_i,

  • changed index: value becomes anything in [0,k-1].

Crucial constraint:

  • If we keep some a_i\ge k, then everything to its right must also be kept and already be nondecreasing; otherwise a changed value (\le k-1) would have to sit after which can break order. So an index with a_i\ge k is keep-eligible only if the suffix is already nondecreasing.

  • If a_i<k, it's always keep-eligible (changed neighbors can be chosen inside [0,k-1] to fit).

We want to maximize the count of kept indices; the rest are changed. Any kept set must be nondecreasing by value. Hence we take the LIS (nondecreasing variant, i.e., -version) over the stream of eligible positions:

\text{eligible}(i):\quad (a[i]<k)\ \ \text{or}\ \ (\text{suf}[i]=0),

where counts descents in . The answer is:

\text{ops}_{\min}=n-\text{LIS}.

Why: kept elements form a nondecreasing subsequence (we never alter them), and every other place can be filled by changed values within [0,k-1] to maintain order. If a kept appears, eligibility enforces a clean nondecreasing suffix with no changed entries after it.

Complexity is \mathcal{O}(n \log n)

def solve():
    n,m,k=map(int,input().split())
    a=list(map(int,input().split()))
    suf=[0]*n
    for i in range(n-2,-1,-1):
        suf[i]=suf[i+1]+(a[i]>a[i+1])
    INF=10**18
    dp=[INF]*(n+1)
    dp[0]=-INF
    lis=0
    for i in range(n):
        if a[i]<k or suf[i]==0:
            l,r,b=1,n,0
            while l<=r:
                mid=(l+r)//2
                if dp[mid]<=a[i]:
                    b=mid;l=mid+1
                else:
                    r=mid-1
            if a[i]<dp[b+1]: dp[b+1]=a[i]
            if b+1>lis: lis=b+1
    print(n-lis)

for _ in range(int(input())):
    solve()