*题解:ABC466F Many Mod Calculation
解析
考虑 \([1,x]\) 中的数 \(\bmod A\) 的分布。以 \(x=7,A=3\) 为例,模完之后范围内的数变为 \(1,2,0,1,2,0,1\),我们每 \(A\) 个分为一组,那么就有两组 \([0,2]\) 加上一个 \(1\),即 \([1,x \bmod A]\)。方便起见,不妨将 \(0\) 也并入原范围中变为 \([0,x]\),这样再取模变为 \(0,1,2,0,1,2,0,1\),同样按每 \(A\) 个分组,原区间就分裂成两组 \([0,A - 1]\) 和一个 \([0,x \bmod A]\)。
根据模运算的性质,当 \(x > A\) 时,\(x \bmod A < \large \frac{x}{2}\),故有效取模次数为 \(O(\log x)\) 次。考虑每次 \(\bmod A_i\) 后区间的分裂情况,对于所有 \([0,x]\) 满足 \(x > A_i\),其分裂后变成 \([0,A_{i} - 1]\) 和 \([0,x \bmod A_i]\)。由于 \([0,A_{i} - 1]\) 是每个 \([0,x]\) 都会分裂出来的,因此区间总数至多加 \(1\),最终至多有 \(N + 1\) 个本质不同区间。而对于每个区间,根据上述性质,其最多通过 \(O(\log x)\) 次减半分裂得到,故总分裂次数为 \(O(N\log x)\)。用一个堆来维护每个本质不同区间,每次取当前所有区间内右端点 \(x\) 最大的进行分裂直至 \(x < A_i\)。
时间复杂度 \(O(N \log x \log N)\)。
代码
/*
*/
#include <bits/stdc++.h>
#define eps 0.0000000001
using namespace std;
typedef long long ll;
typedef unsigned ui;
typedef pair<ll, ll> pii;
const int N = 2e5 + 5, M = 18, P = 450, mod = 1e9 + 7, mod2 = 1e9 + 7, b1 = 131;
ll a[N];
signed main(){
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
int T;
cin>>T;
while(T--){
ll n,x;
cin>>n>>x;
priority_queue<pii> pq;
pq.push({x,1});
for(int i=1;i<=n;i++){
cin>>a[i];
ll cnt2 = 0;
while(!pq.empty() && pq.top().first >= a[i]){
ll tp = pq.top().first;
ll cnt = 0;
while(!pq.empty() && pq.top().first == tp){
cnt += pq.top().second;
pq.pop();
}
pq.push({tp % a[i],cnt});
cnt2 += tp / a[i] * cnt;
}
if(cnt2){
pq.push({a[i] - 1,cnt2});
}
}
ll res = -1;
while(!pq.empty()){
res += pq.top().second;
pq.pop();
}
cout<<res<<'\n';
}
return 0;
}

浙公网安备 33010602011771号