*题解: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;
}
posted @ 2026-07-12 13:30  yutar  阅读(28)  评论(0)    收藏  举报