Many Mod Calculation
Many Mod Calculation
1. 题目描述
给定整数 \(N, X\) 和一个长度为 \(N\) 的正整数序列 \(A = (A_1, A_2, \dots, A_N)\)。
定义函数:
\[f(x) = (\cdots((x \bmod A_1) \bmod A_2) \cdots) \bmod A_N
\]
即对 \(x\) 依次对 \(A_1, A_2, \dots, A_N\) 取模。
目标:求在 \(1 \le x \le X\) 范围内,满足 \(f(x) = 0\) 的整数 \(x\) 的个数。
输入格式
- 第一行:一个整数 \(T\),表示测试用例数。
- 每个测试用例:
- 第一行:两个整数 \(N, X\)
- 第二行:\(N\) 个整数 \(A_1, A_2, \dots, A_N\)
输出格式
对于每个测试用例,输出一行答案。
约束条件
- \(1 \le T \le 2 \times 10^5\)
- \(1 \le N \le 2 \times 10^5\)
- 所有测试用例的 \(N\) 之和不超过 \(2 \times 10^5\)
- \(1 \le X \le 10^{18}\)
- \(1 \le A_i \le 10^{18}\)
- 所有输入值均为整数。
2. 核心思路
2.1 区间表示法
将整数集合用 连续区间 \([0, \text{len})\) 表示,代表整数 \(0, 1, \dots, \text{len}-1\)。
每个区间附带一个 出现次数 cnt,表示该区间内的每个整数都出现了 cnt 次。
初始状态:区间 \([0, X+1)\),出现次数为 \(1\),表示考虑整数 \(0, 1, \dots, X\),最后再减去 \(x=0\)(因为题目要求从 \(1\) 开始)。
2.2 取模操作分解
对区间 \([0, x)\)(出现 cnt 次)应用取模 \(M\)(当 \(x > M\) 时):
- 商:\(q = \left\lfloor \frac{x}{M} \right\rfloor\),余数:\(r = x \bmod M\)
- 分解为:
- \(q\) 个完整的区间 \([0, M)\),每个计数
cnt→ 相当于 \([0, M)\) 总计数增加cnt * q - 若 \(r > 0\),新增区间 \([0, r)\),计数
cnt
- \(q\) 个完整的区间 \([0, M)\),每个计数
关键性质:余数区间长度 \(r < \frac{x}{2}\),因此每个区间最多被分解 \(O(\log X)\) 次。
2.3 高效维护数据结构
使用 std::map<long long, long long>:
- 键(Key):区间长度
len - 值(Value):该区间的出现次数
cnt map自动按键升序排序,因此可通过rbegin()快速获取当前最大区间长度。
优势:
- 自动合并相同长度区间(例如
mp[M] += cnt * q) - 无需优先队列,避免重复元素堆积,提高效率。
3. 预处理:过滤无用的模数
若序列中存在 \(A_i \ge A_{i-1}\),则取模 \(A_i\) 不会改变任何数的值,因为所有数已经小于等于 \(A_{i-1} \le A_i\),取模不变。
因此,只需保留 严格递减 的子序列。
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void solve() {
ll n, x; cin >> n >> x;
vector<ll> a;
for(int i = 0; i < n; i ++) {
ll A; cin >> A;
if(a.empty() || A < a.back()) a.push_back(A);
}
int k = a.size();
map<ll, ll> mp; mp[x + 1] = 1;
for(int i = 0; i < k; i ++) {
ll A = a[i];
while(!mp.empty() && mp.rbegin()->first > A) {
auto it = prev(mp.end());
ll len = it->first, cnt = it->second;
mp.erase(it);
ll q = len / A, r = len % A;
mp[A] += q * cnt;
if(r > 0) mp[r] += cnt;
}
}
ll ans = 0;
for(auto &p : mp) ans += p.second;
cout << ans - 1 << endl;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int t = 1; cin >> t;
while(t --) solve();
return 0;
}

浙公网安备 33010602011771号