【题解】ABC466_f Many Mod Calculation

0

有一个直观的想法是维护所有数模完之后的值是多少

如果对于每个值都做一遍,复杂度直接炸掉

1

发现可以遍历 \(A\),然后整体打包维护一段数的模

设有一组连续的数的模为 \([0,d)\),再用 \(A_i\) 去模

发现可以拆成 \(\lfloor \frac{d}{A_i} \rfloor\)\([0,A_i)\),和一组 \([0,d \mod A_i)\)

2

如果我们暴力维护一段数的模范围,每次暴力用 \(A_i\) 去拆区间

复杂度会直接炸掉

发现有很多组重复的模范围,我们可以直接用 \(k\) 表示其数量

每次拆的时候按照模范围的右边界从大到小处理,适时break剪枝

我们发现需要降序维护 \(([0,d),k)\),发现可以直接用 \(map\) 维护

3

当我们遍历完每个 \(A\) 之后,每个数的模就全部得知

我们直接统计有多少个数模完之后等于 \(0\) ,然后减去 \(1\) 即可( \(0\) 不可以被取到)

4:复杂度

感觉证明不太严谨,不过数量级是对的

对于一个区间 \([0,d)\) 和一个模数 \(A (A<d)\)

则 $d \mod A \times 2 < d $,所以总层数为 \(log(X)\)

每次最多 \(N\) 次遍历,一次遍历 \(map.size()\) 最多增长 \(1\) ,加上 \(map\) 遍历带 \(log\)

总复杂度为 \(O(N \times log(X) \times log(N))\)

5:代码

#include<bits/stdc++.h>
#define int long long
using namespace std;
map<int,int,greater<int> > q;
void solve(){
	int n,x;cin>>n>>x;
	
	q.clear();
	q[x+1]=1;
	while(n--){
		int a;cin>>a;
		for(auto [u,v]:q){
			if(u<=a) break;
			q[a]+=u/a*v;
			if(u%a) q[u%a]+=v;
		}
		while(q.begin()->first>a) q.erase(q.begin());
	}
	int ans=0;
	for(auto [u,v]:q) ans+=v;
	cout<<ans-1<<"\n";
}
signed main(){
	int t;cin>>t;
	while(t--) solve();
	return 0;
}

6:反思

6.1

数学题也可以用非推式子解法来做

6.2

要有整体处理的思想

6.3

因为 \(A>B\) ,所以 \((A\mod B) \times 2<A\)

6.4

map<int,int,greader<int> > q;

存在此写法

posted @ 2026-07-12 19:22  Aistyr  阅读(18)  评论(0)    收藏  举报