「CodeForces575A」Fibonotci

题目链接

点击打开链接

题目概括

给定一个无限长循环序列\(s\),从\(0\)开始标号,开始给定从零开始的循环节\({s_0,s_1\cdots s_{n-1}}\)
然后修改其中的\(m\)项为\(v_i\)
定义\(f_i=s_{i-1}\times f_{i-1}+s{i-2}\times f_{i-2}\)
\(f_k\)。(答案对\(P\)取模)
数据范围 \(n,m\leq 5\times 10^4;s_i,P,p_i\leq 10^{18};v_i\leq 10^9\)

思路要点

用线段树维护循环节。
斐波那契数列用矩阵乘法维护。
对于修改的部分暴力处理。
时间复杂度\(\mathcal O(m\times (log_2 n))\)

代码

#include <bits/stdc++.h>

using namespace std;

const int N = 5e4 + 5;

int MOD, n, m;
long long k;
int s[N];

void add(int& x, int y) {
  x += y;
  if (x >= MOD) {
    x -= MOD;
  }
}

struct Matrix {
  int a[2][2];
  
  Matrix() { }
  
  Matrix(int x) {
    a[0][0] = x;
    a[0][1] = 0;
    a[1][0] = 0;
    a[1][1] = x;
  }
  
  Matrix(int A, int B, int C, int D) {
    a[0][0] = A;
    a[0][1] = B;
    a[1][0] = C;
    a[1][1] = D;
  }
  
  Matrix operator * (Matrix b) {
    Matrix c(0);
    for (int i = 0; i < 2; i++) {
      for (int j = 0; j < 2; j++) {
        for (int k = 0; k < 2; k++) {
          add(c.a[i][j], (long long)a[i][k] * b.a[k][j] % MOD); 
        }
      }
    }
    return c;
  }
};

ostream& operator << (ostream& out, Matrix a) {
  out << " [ ";
  for (int i = 0; i < 2; i++) {
    if (i != 0) {
      out << "   ";
    }
    for (int j = 0; j < 2; j++) {
      out << a.a[i][j] << ' ';
    }
    out << "\n]"[i == 1];
  }
  return out;
}

struct Mdy {
  long long pos;
  int v;
  
  bool operator < (Mdy b) const {
    return pos < b.pos;
  }
};

Mdy mdy[N];

Matrix operator ^ (Matrix x, long long y) {
  Matrix res(1);
  for (; y; y >>= 1, x = x * x) {
    if (y & 1) {
      res = res * x;
    }
  }
  return res;
}

namespace segmentTree {
  Matrix tr[N << 2];
  
  void build(int x, int l, int r) {
    if (l == r) {
      tr[x] = Matrix(s[(l - 1 + n) % n], 1, s[(l - 2 + n) % n], 0);
      return;
    }
    int mid = (l + r) >> 1;
    build(x << 1, l, mid);
    build(x << 1 | 1, mid + 1, r);
    tr[x] = tr[x << 1] * tr[x << 1 | 1];
  }
  
  Matrix query(int x, int l, int r, int ql, int qr) {
    if (ql <= l && r <= qr) {
      return tr[x];
    }
    int mid = (l + r) >> 1;
    Matrix res(1);
    if (ql <= mid) {
      res = res * query(x << 1, l, mid, ql, qr);
    }
    if (qr > mid) {
      res = res * query(x << 1 | 1, mid + 1, r, ql, qr);
    }
    return res;
  }
}
// namespace segmentTree

using namespace segmentTree;

Matrix get(long long l, long long r) {
  if (l > r) {
    return Matrix(1);
  }
  if (l / n == r / n) {
    return query(1, 0, n - 1, l % n, r % n);
  }
  return query(1, 0, n - 1, l % n, n - 1) * (tr[1] ^ (r / n - l / n - 1)) * query(1, 0, n - 1, 0, r % n);
}

int main() {
  scanf("%lld %d %d", &k, &MOD, &n);
  if (k <= 1) {
    printf("%lld\n", k % MOD);
    return 0;
  }
  for (int i = 0; i < n; i++) {
    scanf("%d", &s[i]);
    s[i] %= MOD;
  }
  build(1, 0, n - 1);
  scanf("%d", &m);
  for (int i = 1; i <= m; i++) {
    scanf("%lld %d", &mdy[i].pos, &mdy[i].v);
    mdy[i].v %= MOD;
  }
  sort(mdy + 1, mdy + m + 1);
  while (mdy[m].pos >= k) {
    m--;
  }
//  for (int i = 1; i <= m; i++) {
//    cerr << "debug1 : " << mdy[i].pos << ' ' << mdy[i].v << '\n';
//  }
  Matrix res(1);
  for (int i = 1; i <= m; i++) {
    res = res * get(i == 1 ? 2 : mdy[i - 1].pos + 3, mdy[i].pos);
    int j = i;
    while (j < m && mdy[j + 1].pos - 1 == mdy[j].pos) {
      j++;
    }
    res = res * Matrix(mdy[i].v, 1, s[(mdy[i].pos - 1) % n], 0);
    for (int k = i + 1; k <= j; k++) {
      res = res * Matrix(mdy[k].v, 1, mdy[k - 1].v, 0);
    }
    res = res * Matrix(s[(mdy[j].pos + 1) % n], 1, mdy[j].v, 0);
    i = j;
  }
  res = res * get(m ? mdy[m].pos + 3 : 2, k + 1);
//  cerr << res << '\n';
  printf("%d\n", res.a[0][1]);
  return 0; 
}

猜你喜欢

转载自www.cnblogs.com/chhokmah/p/12315259.html