码迷,mamicode.com
首页 > 其他好文 > 详细

AT2164 AGC006C Rabbit Exercise

时间:2019-06-22 10:55:05      阅读:82      评论:0      收藏:0      [点我收藏+]

标签:logs   包含   const   --   lock   zha   数组   print   c++   

AT2164 AGC006C Rabbit Exercise

数轴上有 \(n\) 个点,每个点的坐标为 \(a_i\) 。一轮操作包含 \(m\) 次变换,第 \(i\) 次将 \(b_i(1<b_i<n)\) 随机跳到点关于 \(b_i-1\)\(b_i+1\) 的对应点。求 \(k\) 轮操作后每个点的期望位置

\(n,\ m\leq10^5,\ k\leq10^{18},\ |a_i|\leq10^9\)

期望,差分,倍增


假设点 \(a_i\) 变换后坐标为 \(x\) ,则 \(\frac{a_i+x}{2}=a_{i-1}\)\(a_{i+1}\) ,即 \(x=2a_{i-1}-a_i\)\(2a_{i+1}-a_i\) ,两式相加得 \(x=a_{i-1}+a_{i+1}-a_i\) ,即为变换后坐标期望值。

考虑类似题目 CF1110E Magic Stones 的做法,将原序列差分得到 \(c_i\) ,可以发现对 \(a_i\) 的变换相当于交换了 \(c_i,\ c_{i+1}\)

可以发现 \(k\) 轮操作相对顺序不影响答案,由于变换两次相当于变换一次后再变换一次,变换四次相当于变换两次后再变换两次,于是可以考虑倍增

可以 \(O(n)\) 求出一轮操作后差分数组的排列,倍增的预处理可以用排列完成

时间复杂度 \(O(k\log n)\)

代码

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

typedef long long ll;
const int maxn = 1e5 + 10;
ll k, a[maxn];
int n, m, data[maxn], pos[61][maxn];

int main() {
  scanf("%d", &n);
  for (int i = 1; i <= n; i++) {
    scanf("%lld", a + i), data[i] = i;
  }
  scanf("%d %lld", &m, &k);
  for (int i = 1, x; i <= m; i++) {
    scanf("%d", &x);
    swap(data[x], data[x + 1]);
  }
  for (int i = 1; i <= n; i++) {
    pos[0][i] = data[i];
  }
  for (int i = 1; i < 61; i++) {
    for (int j = 1; j <= n; j++) {
      pos[i][j] = pos[i - 1][pos[i - 1][j]];
    }
  }
  for (int i = 1; i <= n; i++) {
    data[i] = i;
  }
  for (int p = 60; ~p; p--) {
    if (k >> p & 1) {
      for (int i = 1; i <= n; i++) {
        data[i] = pos[p][data[i]];
      }
    }
  }
  static int c[maxn];
  for (int i = 1; i <= n; i++) {
    c[i] = a[i] - a[i - 1];
  }
  for (int i = 1; i <= n; i++) {
    a[i] = a[i - 1] + c[data[i]];
    printf("%lld\n", a[i]);
  }
  return 0;
}

AT2164 AGC006C Rabbit Exercise

标签:logs   包含   const   --   lock   zha   数组   print   c++   

原文地址:https://www.cnblogs.com/Juanzhang/p/11067783.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!