C

我们先定义两种计算:

  1. 前向,即给出 ,计算 这个序列的和,其中序列长为
  2. 反向,即给出 ,计算 这个序列的和,其中序列长为

然后我们可以把新牌堆分拆成上下两部分:下面 张牌,上面 张牌,分别计算这两个部分对答案的贡献。

先分析下面 张牌的成分。一开始做了 次操作后,原牌堆自底向上变成:

其中

然后下面的 张牌中:

  1. 自底向上的第 张牌,对应原牌堆自底向上的第 张牌。
  2. 自底向上的第 张牌,对应原牌堆自顶向下的第 张牌。

那么如果要计算自底向上 区间的牌的和,可以换回到原牌堆求解。具体而言,结果就是前向计算 和后向计算 的和。如果要计算 的和可以用前缀和减一下。

再分析上面 张牌的成分。这部分比较简单,只要算出第 张牌的值然后用前向计算即可。

由于所有运算都可以 完成,因此总的时间复杂度为

PS:这题不要忘了取模,比赛的时候我有一个运算忘了取模直接就炸了。。。

const long long M = 998244353;
class Solution {
    long long m_, b1, b2;
    inline long long addto(long long l, long long r){
        return ((l + r) * (r - l + 1) >> 1ll) % M;
    }
    inline long long modadd(long long x, long long y){
        return (x + y >= M ? x + y - M: x + y);
    }
    long long forward(long long base, long long lft){
        long long res = 0;
        if (lft >= m_ - base + 1ll){
            lft -= m_ - base + 1ll, res = addto(base, m_); 
            res = modadd(res, (lft / m_) * addto(1ll, m_) % M);
            lft %= m_;
            if (lft > 0) res = modadd(res, addto(1ll, lft));
        }else {
            res = addto(base, base + lft - 1);
        }
        return res;
    }
    long long backward(long long base, long long lft){
        long long res = 0;
        if (lft >= base - 1){
            lft -= base - 1ll, res = addto(1, base - 1);
            res = modadd(res, 1ll * (lft / m_) * addto(1ll, m_) % M);
            lft %= m_;
            if (lft > 0) res = modadd(res, addto(m_ - lft + 1, m_));
        }else {
            res = addto(base - lft, base - 1);
        }
        return res;
    }
    long long q1(long long r){
        if (r == 0ll) return 0;
        long long hf = r >> 1;
        return modadd(forward(b1, r - hf), backward(b1, hf));
    }
    long long q2(long long r){
        if (r == 0ll) return 0ll;
        return forward(b2, r);
    }
public:
    long long work(long long n, long long m, long long a, long long b, long long x, long long y) {
        b1 = a % m + 1, b2 = (b1 - 1 + b) % m + 1;
        m_ = m;
        long long ans = 0;
        if (x <= 2ll * b){
            ans = modadd(ans, M - q1(x - 1));
            ans = modadd(ans, q1(min(2ll * b, y)));
        }
        if (y > 2ll * b){
            ans = modadd(ans, M - q2(max(2 * b, x - 1) - 2 * b));
            ans = modadd(ans, q2(y - 2 * b));
        }
        return ans;
    }
};