P9668 [ICPC2022 Jinan R] Torch 题解

思路#

考虑使用矩阵模拟这个过程。

首先,我们可以设初值为:

[01]

表示瘦子初始走 0 米,胖子初始走 1 米。

考虑瘦子走一步。

由于瘦子每走一步都不能超过胖子,我们可以使用 (min,+) 矩乘来维护这个性质。

那么瘦子走一步是:

[1inf10]

同样,胖子走一步是:

[0infinf1]

不走是:

[0infinf0]

我们可以把每个循环中的所有过程求出来。

由于循环的长度是 lcm(a1+b1,a2+b2)

我们将相邻的合并以后就只会有最多 2(a1+b1+a2+b2) 项。

做一个前缀和即可。

时间复杂度:O(nlogn)

可能会有一点卡空间,卡一卡就可以了。

Code#

/*
  ! 以渺小启程,以伟大结束。
  ! Created: 2024/07/03 09:01:00
*/
#include <bits/stdc++.h>
using namespace std;

#define x first
#define y second
#define int long long
#define mp(x, y) make_pair(x, y)
#define eb(...) emplace_back(__VA_ARGS__)
#define fro(i, x, y) for (int i = (x); i <= (y); i++)
#define pre(i, x, y) for (int i = (x); i >= (y); i--)
inline void JYFILE19();

using i64 = long long;
using PII = pair<int, int>;

bool ST;
const int N = 1e6 + 10;
const int I = 1e18 + 10;
const int mod = 998244353;

struct Mat {
  int a00, a01, a10, a11;
  inline friend Mat operator*(const Mat&a, const Mat&b) {
    return {
      min(a.a00 + b.a00, a.a01 + b.a10),
      min(a.a00 + b.a01, a.a01 + b.a11),
      min(a.a10 + b.a00, a.a11 + b.a10),
      min(a.a10 + b.a01, a.a11 + b.a11)
    };
  }
};
const Mat sz = {1, I,-1, 0};
const Mat pz = {0, I, I, 1};
const Mat sj = {0, I, I, 0};
const Mat pj = {0, I, I, 0};
struct Nod {
  int a00, a01;
  inline friend Nod operator*(const Nod&a, const Mat&b) {
    return {
      min(a.a00 + b.a00, a.a01 + b.a10),
      min(a.a00 + b.a01, a.a01 + b.a11)
    };
  }
};

int q[N];
int t[N * 8];
Mat d[N];
Mat c[N * 8];

inline Mat power(Mat x, int y) {
  Mat res = x; y--;
  while (y) {
    if (y & 1) res = res * x;
    x = x * x, y /= 2;
  }
  return res;
}

inline void solve() {
  int a1, b1, a2, b2, n;
  cin >> a1 >> b1;
  cin >> a2 >> b2;
  cin >> n;
  Nod cs = {0, 1};
  int p1 = 0, p2 = 0, s1 = 0, s2 = 0, p = 0, ti = 0;
  Mat zy;
  do {
    Mat cur;
    int sy = 1e9;
    if (p1 == 0) cur = pz, sy = min(a1 - s1, sy);
    if (p1 == 1) cur = pj, sy = min(b1 - s1, sy);
    if (p2 == 0) cur = cur * sz, sy = min(a2 - s2, sy);
    if (p2 == 1) cur = cur * sj, sy = min(b2 - s2, sy);
    ++p, t[p] = sy, c[p] = cur, ti += t[p];
    s1 += sy, s2 += sy;
    if (p1 == 0 && s1 == a1) p1 = 1, s1 = 0;
    if (p1 == 1 && s1 == b1) p1 = 0, s1 = 0;
    if (p2 == 0 && s2 == a2) p2 = 1, s2 = 0;
    if (p2 == 1 && s2 == b2) p2 = 0, s2 = 0;
  } while (p1 || p2 || s1 || s2);
  fro(i, 1, p) t[i] = t[i - 1] + t[i];
  fro(i, 1, n) {
    cin >> q[i];
    int w = q[i], l = w / ti;
    if (l) {
      w -= ti * l;
    }
    if (w) {
      int x = upper_bound(t + 1, t + p + 1, w) - t;
      d[i] = c[x];
    }
  }
  fro(i, 1, p) c[i] = power(c[i], t[i] - t[i - 1]);
  fro(i, 2, p) c[i] = c[i - 1] * c[i];
  fro(i, 1, n) {
    Nod ed = cs;
    int l = q[i] / ti;
    if (l) {
      ed = ed * power(c[p], l), q[i] -= ti * l;
    }
    if (q[i]) {
      int x = upper_bound(t + 1, t + p + 1, q[i]) - t;
      if (x - 1)
        ed = ed * c[x - 1], q[i] -= t[x - 1];
      if (q[i])
        ed = ed * power(d[i], q[i]);
    }
    cout << ed.a00 << "\n";
  }
}

signed main() {
  JYFILE19();
  int t;
  cin >> t;
  while (t--) {
    solve();
  }
  return 0;
}

bool ED;
inline void JYFILE19() {
  // freopen("", "r", stdin);
  // freopen("", "w", stdout);
  srand(random_device{}());
  ios::sync_with_stdio(0), cin.tie(0);
  double MIB = fabs((&ED - &ST) / 1048576.), LIM = 1024;
  cerr << "MEMORY: " << MIB << endl, assert(MIB <= LIM);
}

作者:JiaY19

出处:https://www.cnblogs.com/JiaY19/p/18287915

版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。

posted @   JiaY19  阅读(42)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示