P2261 [CQOI2007]余数求和
G ( n , k ) = ∑ i = 1 n k m o d i = ∑ i = 1 n ( k − i ∗ [ k i ] ) = n k − ∑ i = 1 n i ∗ [ k i ] \begin{aligned} G(n,k)&=\sum_{i=1}^nk\ mod \ i\\ &=\sum_{i=1}^n(k-i*[\frac{k}{i}])\\ &=nk-\sum_{i=1}^ni*[\frac{k}{i}] \end{aligned} G(n,k)=i=1∑nk mod i=i=1∑n(k−i∗[ik])=nk−i=1∑ni∗[ik]
- 以 k = 6 k=6 k=6 为例:
i i i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
---|---|---|---|---|---|---|---|---|---|---|---|
[ k i ] [\frac{k}{i}] [ik] | 6 6 6 | 3 3 3 | 2 2 2 | 1 1 1 | 1 1 1 | 1 1 1 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 | 0 0 0 |
- 发现 [ k i ] [\frac{k}{i}] [ik] 被分为了 4 4 4 块,可以用整除分块来计算
- 整除分块的时间复杂度 O ( 2 k ) O(2\sqrt k) O(2k) , ( [ k i ] [\frac{k}{i}] [ik] 约有 2 k 2\sqrt k 2k 个值 )
#include <bits/stdc++.h>
#define int long long
using namespace std;
signed main()
{
ios_base::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int n,k;
cin>>n>>k;
int ans=n*k;
for(int l=1,r;l<=n;l=r+1)
{
int t=k/l; // 即 k/i
if(t) r=min(k/t,n); // 确定右端点
else r=n;
ans -= t*(r-l+1)*(l+r)>>1; // 表示区间[l,r]的贡献,别忘了除2
}
cout<<ans<<endl;
return 0;
}