【题解】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;
存在此写法

浙公网安备 33010602011771号