2 条题解

  • 1
    @ 2025-10-17 0:03:40

    P10843 【MX-J2-T4】Turtle and Cycles 题解

    解题思路

    首先,观察操作的本质。设 x=a(i1)modnx = a_{(i-1) \bmod n}, y=aiy = a_i, z=a(i+1)modnz = a_{(i+1) \bmod n},那么操作将 aia_i 变为 x+zyx + z - y。考虑差分数组,定义 bi=aiai1b_i = a_i - a_{i-1}(环形处理,a1=an1a_{-1} = a_{n-1})。操作前,bi=yxb_i = y - x, bi+1=zyb_{i+1} = z - y;操作后,bi=(x+zy)x=zy=bi+1b_i' = (x+z-y) - x = z - y = b_{i+1}, bi+1=z(x+zy)=yx=bib_{i+1}' = z - (x+z-y) = y - x = b_i。因此,一次操作相当于交换了相邻的差分值 bib_ibi+1b_{i+1}

    一个位置 ii 是好的当且仅当 ai1<aia_{i-1} < a_iai+1<aia_{i+1} < a_i。在差分数组上,这等价于 bi>0b_i > 0bi+1<0b_{i+1} < 0。定义二进制序列 si=1s_i = 1 如果 bi>0b_i > 0,否则 si=0s_i = 0。那么好位置对应 si=1s_i = 1si+1=0s_{i+1} = 0 的位置。

    序列是好的当且仅当恰好有一个好位置,即在环形序列中恰好有一个 si=1s_i = 1si+1=0s_{i+1} = 0 的位置。这在环形二进制序列中意味着所有 11 是连续的,所有 00 是连续的(即序列形如 111000111\ldots000000111000\ldots111,但根据差分条件,需要的是 1100 的变化点)。

    通过操作交换相邻差分值,我们可以重新排列差分数组。问题转化为:通过相邻交换,将二进制序列 ss 排列成所有 11 连续的形式(即连续 11 后接连续 00),所需的最小交换次数。

    最小交换次数的计算等价于将所有的 11 移动到连续位置所需的最小移动步数。设 11 的个数为 kk11 的位置为 q1,q2,,qkq_1, q_2, \ldots, q_k(排序后)。目标是将这些 11 移动到连续位置 L,L+1,,L+k1L, L+1, \ldots, L+k-1。最小交换次数为 minLj=1kqj(L+j1)\min_L \sum_{j=1}^k |q_j - (L+j-1)|

    在环形序列中,需要处理环的循环特性。一个常见技巧是将序列复制一份,然后计算线性序列上的最小代价。

    算法实现

    根据排列 aa 计算差分值 bi=aiai1b_i = a_i - a_{i-1} ,并生成二进制序列 si=[bi>0]s_i = [b_i > 0]

    ss 复制一份得到长度为 2n2n 的序列,以便处理环形。

    f[i]f[i] 表示 s[1..i]s[1..i]11 的个数。

    g[i]g[i] 表示 s[1..i]s[1..i]11 的索引加权和(即 j=1ijsj\sum_{j=1}^i j \cdot s_j)。

    sg[i]sg[i] 表示 s[i..2n]s[i..2n]11 的逆序索引加权和(逆序索引为 2nj+12n-j+1)。

    计算最小代价:对于每个可能的起始位置 ii1in1 \leq i \leq n),将环形序列视为从 ii 开始的长度为 nn 的段,计算将 11 移动到该段前半部分和后半部分的代价:

    左半部分[i,mid]:[i, \text{mid}]:\\ 代价:lres=g[mid]g[i1]lki(lk1)lk/2lres = g[mid] - g[i-1] - lk * i - (lk-1)*lk/2

    右半部分[mid+1,i+n1]:[\text{mid}+1, i+n-1]:\\ 代价:$rres = sg[mid+1] - sg[i+n] - rk * (2*n - (i+n-1) + 1) - (rk-1)*rk/2$

    总代价为 lres+rres lres + rres ,取最小值。

    复杂度分析 时间复杂度:O(Σn)O(\Sigma n)

    空间复杂度:O(n)O(n)

    Code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=4e5+5;
    int t, n, a[N];
    ll g[N],f[N],sg[N];
    bool b[N];
    ll cal(int n){
        ll ans=1e18;
        for(int i=1; i<=n; i++) {
            int mid=i+n/2-1;
            ll lk=f[mid]-f[i-1];
            ll lres=g[mid]-g[i-1]-lk*i-(lk-1)*lk/2;
            ll rk=f[i+n-1]-f[mid];
            ll rres=sg[mid+1]-sg[i+n]-rk*(2*n-(i+n-1)+1)-(rk-1)*rk/2;
            ans = min(ans,lres+rres);
        }
        return ans;
    }
    
    void solve() {
        cin>>n;
        for(int i=1; i<=n; i++) {
    		cin>>a[i];
            a[i+n]=a[i];
        }
        for(int i=2; i<=n+1; i++) {
            b[i-1]=(a[i]>a[i-1]);
            b[i-1+n]=b[i-1];
        }
        int tot = 2*n;
        for(int i=1; i<=tot; i++) {
            f[i]=f[i-1]+b[i];
            g[i]=g[i-1]+i*b[i];
        }
        sg[tot+1]=0;
        for(int i=tot,j=1; i>=1; i--,j++) {
            sg[i]=sg[i+1]+j*b[i];
        }
        cout<<cal(n)<<'\n';
    }
    
    int main(){
        ios::sync_with_stdio(0);
        cin.tie(0);
        cout.tie(0);
        cin>>t;
        while(t--) solve();
        return 0;
    }
    

    (这是本蒟蒻的第一篇题解,不喜勿喷,QAQ)

    • -5
      @ 2024-9-12 13:01:34

      标题

      思路

      解题方法

      复杂度

      时间复杂度:

      添加时间复杂度, 示例: O(n)O(n)

      空间复杂度:

      添加空间复杂度, 示例: O(n)O(n)

      Code

      • 1

      信息

      ID
      24
      时间
      1000ms
      内存
      512MiB
      难度
      6
      标签
      递交数
      478
      已通过
      28
      上传者