zoukankan      html  css  js  c++  java
  • ARC127F ±AB

    题目链接

    首先,若 (A + B le M +1),根据 periodicity lemma 可以得到每个点均可达。

    排除这种情况后,考虑:

    • (V ge B),令 (V gets V - B)
    • 否则若 (V +A le M),令 (V gets V+A)
    • 否则停止

    (V < A + B),且忽略 (M) 的限制,则 (V) 可以不重复地遍历 ([0, A + B)) 中的所有数(只需要注意到 ([A, A + B)) 中的所有数都会被遍历一次,随后不断减 (B)

    但是有 (A + B > M + 1),因此这个环中至少有一个数不可达。

    现在从起点开始向环上两个方向走(即对 ((A, B)), ((B, A)) 分别重复以上过程,将经过的数个数相加即可。

    下面证明所有可达的点都可以在这个环上达到:

    在一步可达的点之间连一条边,则在上述条件下每个点的度数至多为 (2)

    通过分类讨论得知((V - A ge 0)(V + B le M),两者不同时成立),如果我们构造的环没有包括原图上的边会产生矛盾。


    现在需要计数上面的操作次数。

    重新描述问题,求出最小的 (k),满足

    [egin{aligned} &(V + kA) mod B > M - A\ iff& M - A + 1 - (V mod B) oldsymbolle kA mod B oldsymbolle B - 1 - (V mod B) end{aligned} ]

    (V mod B + A > M) 的情况答案可以直接算出)

    可以将问题再次描述为:高 (A)(B) 的矩形上,从 ((0, 0)) 出发向 (y = x) 方向走,如果超出某个边界就移动到对侧,第一次经过 (y = 0, x in [l, r])(x)。之后只需用 exgcd 就可以解出 (k)

    这个问题直接递归就可以解决。(注意 ([l, r]) 可能是一段前缀和一段后缀组成的区间)

    下面是这个过程的示意图(来自 atcoder)

    algo-description

    复杂度为对数级别。

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #include <numeric>
    #include <cassert>
    using namespace std;
    
    #define LOG(f...) fprintf(stderr, f)
    #define DBG(f...) printf("%3d: ", __LINE__), printf(f)
    // #define DBG(f...) void()
    #define all(cont) begin(cont), end(cont)
    #ifdef __linux__
    #define getchar getchar_unlocked
    #define putchar putchar_unlocked
    #endif
    
    using ll = long long;
    
    template <class T> void read(T &x) {
      char ch; x = 0;
      int f = 1;
      while (isspace(ch = getchar()));
      if (ch == '-') ch = getchar(), f = -1;
      do x = x * 10 + (ch - '0'); while(isdigit(ch = getchar()));
      x *= f;
    }
    template <class T, class ...A> void read(T &x, A&... args) { read(x); read(args...); }
    
    pair<int, int> exgcd(int a, int b) {
      if (!b) return {1, 0};
      auto [x, y] = exgcd(b, a % b);
      return {y, x - a / b * y};
    }
    int inv(int x, int M) {
      int t = exgcd(x, M).first;
      return t < 0 ? t + M : t;
    }
    
    int recur(int h, int w, int l, int r) {
      int pos = (l + h - 1) / h * h % w;
      if ((l <= pos && pos <= r) || (l > r && (pos <= r || pos >= l)))
        return pos >= l ? pos - l : pos - l + w;
      if (h >= w) return recur(h % w, w, l, r);
      return (r - l) - recur(w % h, h, (h - r % h) % h, (h - l % h) % h);
    }
    
    int solve(int a, int b, int m, int v) {
      int vmb = v % b;
      if (vmb > m - a) return v / b;
      int r = recur(a, b, m + 1 - a - vmb, b - 1 - vmb) + (m + 1 - a - vmb);
      int k = (ll)r * inv(a, b) % b;
      return k + (((ll)k * a + v) / b);
    }
    
    int main() {
    #ifndef ONLINE_JUDGE
      freopen("input.txt", "r", stdin);
      freopen("output.txt", "w", stdout);
    #endif
      int T;
      read(T);
      while (T--) {
        int a, b, m, v;
        read(a, b, v, m);
        if (a + b <= m + 1) {
          printf("%d
    ", m + 1);
          continue;
        }
        printf("%d
    ", solve(a, b, m, v) + solve(b, a, m, v) + 1);
      }
      return 0;
    }
    
    
  • 相关阅读:
    文件处理--文件操作
    三元运算
    alex 推荐的书
    python字符串、列表和字典的说明
    运算符
    while else语句
    格式化输出
    数据类型-元组
    数据类型-集合
    字符串
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/sol-arc127f.html
Copyright © 2011-2022 走看看