形式化题意
设
\f(x)=(\\dots((x\\bmod A_1)\\bmod A_2)\\dots)\\bmod A_n \\
即依次对 \(A_1,A_2,\dots,A_n\) 取模。
求
\\\sum_{k=1}\^{X}\[f(k)=0 \]
的值。
Solution
考虑所有 \(x = 0,1,\dots,X\) 依次对 \(A_1,A_2,\dots,A_N\) 取模的过程。初始时这些数构成一个半开区间 \([0, X+1)\)。第 \(i\) 步对 \(A_i\) 取模,会把当前每个区间 \([0,d)\) 分拆成:
- \(\lfloor d/A_i\rfloor\) 个 \([0,A_i)\)
- \(1\) 个 \([0,d\bmod A_i)\)(若 \(d\bmod A_i\neq 0\))
我们可以维护所有区间并将右端点相同的区间合并。具体地,用一个 map 维护每个右端点 \(d\) 对应的区间 \([0,d)\) 出现次数。然后直接按照上述过程模拟即可。
复杂度分析:第 \(i\) 步中,对于区间 \([0,d)\) 取模 \(A_i\) 时若 \(d\ge A_i\) 则必有 \(d\bmod A_i<d/2\)。这一步还会产生 \([0,A_i)\) 区间。因此在整个过程中出现过的本质不同区间共有 \(O(N\log X)\) 个,因此总时间复杂度 \(O(N\log X\log N)\)。
Code
cpp
#include <bits/stdc++.h>
#define rept(i,a,b) for(int i(a);i<=b;++i)
#define fi first
#define se second
#define int long long
using namespace std;
constexpr int N=2e5+5;
int n,x,a[N];
map<int,int,greater<int>> mp;
void solve(){
cin>>n>>x;
mp.clear();
mp[x+1]=1;
rept(i,1,n) cin>>a[i];
rept(i,1,n){
for(auto it=mp.begin();it!=mp.end();++it){
if(it->fi<=a[i]) break;
int q=it->fi/a[i],r=it->fi%a[i];
mp[a[i]]+=q*it->se;
if(r) mp[r]+=it->se;
}
while(mp.begin()->fi>a[i]) mp.erase(mp.begin());
}
int ans=0;
for(auto it=mp.begin();it!=mp.end();++it){
ans+=it->se;
}
cout<<ans-1<<'\n';
}
signed main(){
int T;
cin>>T;
while(T--) solve();
return 0;
}