• AT2164 [AGC006C] Rabbit Exercise


    首先我们可以考虑一下 (x) 关于 (y) 的对称点的坐标,不难发现就是 (x + 2 imes (y - x)),那么期望的增量就会增加 (2 imes (y - x))。不难发现我们可以令 (dp_{i, j}) 表示 (j)(i) 次操作(即假设进行了 (p) 轮操作,当前是第 (q) 次操作,则 (i = (p - 1) imes m + q)),则会有转移:

    [dp_{i, a_q} += frac{1}{2} imes 2 imes (dp_{i - 1, a_q - 1} - dp_{i - 1, a_q}) + frac{1}{2} imes 2 imes (dp_{i - 1, a_q + 1} - dp_{i - 1, a_q}) ]

    即:

    [dp_{i, a_q} += dp_{i - 1, a_q - 1} + dp_{i - 1, a_q + 1} - 2 imes dp_{a_q} ]

    可以发现第一维可以直接压去,则有转移 (i = a_q)

    [dp_i += dp_{i - 1} + dp_{i + 1} - 2 imes dp_i ]

    你会发现这个转移非常有特色,实际上可以将上式划成两个部分:

    [dp_i += (dp_{i + 1} - dp_i) - (dp_i - dp_{i - 1}) ]

    你会发现这实际上是两个差分数在相加,令 (f_i = dp_i - dp_{i - 1}),即:

    [dp_i = f_{i + 1} - f_i ]

    显然这样算是非常不方便的,我们干脆考虑差分数组 (f) 的变化,则有:

    [f_i += f_{i + 1} - f_i Leftrightarrow f_i = f_{i + 1} ]

    [f_{i + 1} -= f_{i + 1} - f_i Leftrightarrow f_{i + 1} = f_i ]

    相当于将差分数组 (f_i, f_{i + 1}) 交换!那么问题转化为,给你一个序列,有 (K) 轮变换,每次变换有 (m) 次操作,按照给定的操作序列 (a_i) 交换 (f_{a_i}, f_{a_i + 1})。因为每轮变换的操作序列都是一样的,这意味着每个位置在一轮之后变到的位置是一样的。于是我们先暴力将经过一轮操作后位置排列 (P) 变换到的位置序列 (P')(事实上我们成排列 (P ightarrow P') 的这样一个过程叫做置换),对于置换而言一个常见的想法就是对 (P_i ightarrow P'_i) 连一条边,这样将形成一张若干个简单环组成的有向图。那么每个位置经过 (K) 轮置换后的位置就相当于它在这个简单环上走 (K) 步后的位置,这个就很容易可以算出来了。

    可以发现,上面这个做法的复杂度是 (O(n + m)) 的,非常地优秀!

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    #define rep(i, l, r) for(int i = l; i <= r; ++i)
    const int N = 100000 + 5;
    bool book[N];
    int n, m, k, tmp, cnt, a[N], d[N], p[N], dp[N], nxt[N], ans[N];
    vector <int> G[N];
    int read(){
        char c; int x = 0, f = 1;
        c = getchar();
        while(c > '9' || c < '0'){ if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    signed main(){
        n = read();
        rep(i, 1, n) d[i] = read(), p[i] = i, dp[i] = d[i] - d[i - 1];
        m = read(), k = read();
        rep(i, 1, m) a[i] = read(), swap(p[a[i]], p[a[i] + 1]);
        rep(i, 1, n) nxt[i] = p[i]; 
        rep(i, 1, n) if(!book[i]){
            int x = i; G[++cnt].push_back(i), book[i] = true;
            while(nxt[x] != i) x = nxt[x], book[x] = true, G[cnt].push_back(x);
        }
        rep(i, 1, cnt){
            int S = G[i].size(), tr = k % S;
            rep(j, 0, S - 1) ans[G[i][j]] = dp[G[i][(j + tr) % S]];
        }
        rep(i, 1, n) tmp += ans[i], printf("%lld.0
    ", tmp);
        return 0;
    }
    
    
    GO!
  • 相关阅读:
    VS2019离线包获取-安装-更新
    http升级https:IIS配置HTTPS
    http升级https:使用XCA生成的证书测试
    俺的分布式架构系统之计算机网络7
    俺的分布式架构系统之计算机网络6
    俺的分布式架构系统之计算机网络5
    俺的分布式架构系统之计算机网络4
    俺的分布式架构系统之计算机网络3
    俺的分布式架构系统之计算机网络2
    iOS Team Inhouse Provisioning Profile 刷新过期时间问题
  • 原文地址:https://www.cnblogs.com/Go7338395/p/13661678.html
Copyright © 2020-2023  润新知