[Leaf] [ABC443G] Another Mod of Linear Problem

g---another-mod-of-linear-problem">G - Another Mod of Linear Problem

1. 题面梗概

中译中: 给定序列 Xk=(Ak+B) mod MX_k = (Ak + B) \bmod M,在 0≤k<N0 \leq k < N 的范围内,统计有多少个 kk 满足 Xk>kX_k > k。

2. 逻辑推导

这显然是一个数学推导问题,我们从公式和限制条件入手分析。

取模定义得:Xk=(Ak+B)(modM)  ⟹  Xk=(Ak+B)−M⋅⌊Ak+BM⌋X_k = (Ak + B) \pmod M \implies X_k = (Ak + B) - M \cdot \lfloor \frac{Ak + B}{M} \rfloor 。

我们要统计 Xk≤kX_k \leq k 的情况,代入不等式,整理得到:

(A−1)k+B≤M⌊Ak+BM⌋  ⟹  (A−1)k+BM≤⌊Ak+BM⌋(A - 1)k + B \leq M \lfloor \frac{Ak + B}{M} \rfloor \implies \frac{(A-1)k + B}{M} \leq \lfloor \frac{Ak + B}{M} \rfloor

由于 ⌊Ak+BM⌋\lfloor \frac{Ak + B}{M} \rfloor 是一个整数,所以不等式还可以进一步变形:

⌊(A−1)k+B−1M⌋<⌊Ak+BM⌋\lfloor \frac{(A - 1)k + B - 1}{M} \rfloor < \lfloor \frac{Ak + B}{M} \rfloor

因为 A−1<AA - 1 < A,所以 ⌊(A−1)k+B−1M⌋\lfloor \frac{(A - 1)k + B - 1}{M} \rfloor 至多比 ⌊Ak+BM⌋\lfloor \frac{Ak + B}{M} \rfloor 小 11。因此,指示函数 f(Xk≤k)f(X_k \leq k) 就可以写成:

f(Xk≤k)=⌊Ak+BM⌋−⌊(A−1)k+B−1M⌋f(X_k \leq k) = \lfloor \frac{Ak + B}{M} \rfloor - \lfloor \frac{(A - 1)k + B - 1}{M} \rfloor

结论:答案就是总数减去不符合条件的数量

Ans=N−∑k=0N−1(⌊Ak+BM⌋−⌊(A−1)k+B−1M⌋)Ans = N - \sum_{k=0}^{N-1}(\lfloor \frac{Ak + B}{M} \rfloor - \lfloor \frac{(A - 1)k + B - 1}{M} \rfloor )

而这种形如 ∑i=0N(⌊ai+bc⌋)\sum_{i=0}^{N}( \lfloor \frac{ai+b}{c} \rfloor) 的求和,可以采用类欧几里得算法 floor_sum( n, m, a, b) 在 O(log⁡m)O(\log m) 时间内求出。具体逻辑证明就不在这里列出了。

3. 代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
using ull = __int128;

ull calc( ll a, ll b, ll c, ll n )
{
ull ans = 0;
if( a >= c )
{
ans += (ull)n * (n + 1) / 2 * ( a / c );
a %= c;
}
if( b >= c )
{
ans += (ull)(n + 1) * ( b / c );
b %= c;
}
ull m = ( a * n + b ) / c;
if( m == 0 ) return ans;
return ans + m * n - calc( c, c - b - 1, a, m - 1 );
}

void solve( )
{
ll n, m, a, b;
cin >> n >> m >> a >> b;

// 注意特殊判断 A == 0 的情况
if( a == 0 )
{
cout << min( n, b ) << '\n';
return;
}

ull s1 = calc( a, b, m, n - 1 );
ull s2 = calc( a - 1, b - 1, m, n - 1 );

// 还有特殊的 B == 0 的情况
if( b == 0 ) s2 = calc( a - 1, m - 1, m, n - 1 ) - n;

cout << n - (ll)(s1 - s2) << '\n';
}

int main( )
{
ios::sync_with_stdio(0);
cin.tie(0); cout.tie(0);
int _t = 1;
cin >> _t;
while( _t -- ) solve( );
return 0;
}

4. 复盘

  • 复杂度: O(Tlog⁡M)O(T \log M)。

  • 碎碎念: 残念!!!就差一点特判我就AK了,这题难点有三个,第一是推导数学公式的能力,第二是类欧几里得算法的掌握,第三就是细节了,边界情况,爆 longlong。

  • 关联笔记: [[类欧几里得算法]]


[Leaf] [ABC443G] Another Mod of Linear Problem
http://miqiu.space/posts/cbc2f5b3/
作者
Miqiu
发布于
2026年1月31日
许可协议