BZOJ 1257(分块思想)

题意: 给定 n , k n,k n,k,问 ∑ i = 1 n k   m o d   i \sum_{i=1}^{n}k\bmod i i=1nkmodi,其中 1 ≤ n , k ≤ 1 0 9 1\leq n,k\leq 10^9 1n,k109

题解:
由: k   m o d   i = k − ⌊ k i ⌋ × i k \bmod i = k - \lfloor \frac{k}{i} \rfloor \times i kmodi=kik×i
得: ∑ i = 1 n k   m o d   i = n × k − ∑ i = 1 n ⌊ k i ⌋ × i \sum_{i=1}^{n}k\bmod i = n\times k - \sum_{i=1}^n \lfloor \frac{k}{i} \rfloor\times i i=1nkmodi=n×ki=1nik×i

可以知道一定有一些数 i i i ⌊ k i ⌋ \lfloor \frac{k}{i} \rfloor ik相同,这里采用分块思想:
同一块数的 ⌊ k i ⌋ \lfloor \frac{k}{i} \rfloor ik相同,长度为 m i n ( n , k / ( k / i ) ) − i + 1 min(n, k / (k / i)) - i + 1 min(n,k/(k/i))i+1,这里的 i i i是一个块的左端点, m i n ( n , k / ( k / i ) ) min(n, k / (k / i)) min(n,k/(k/i))是一个块的右端点。
这里考虑 k k k n n n大小关系

  • k ≤ n k\leq n kn时,自然是 k k k的所有值大于 0 0 0分块全部算上,所以当某个分块为 0 0 0时,直接设右边为 n n n即可,下一步就可以结束计算了。
  • k > n k>n k>n时, k k k的分块某些部分不能被算上,所以每次枚举右端点时,要取 m i n ( n , r ) min(n,r) min(n,r),保证取的分块不会大于 n n n

代码:

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;
const int N = 1e5 + 10;

struct Node{
	int x, y;
};

inline ll read() {
	ll x = 0, f = 1;
	char ch = getchar();
	while(!isdigit(ch)) {if(ch == '-') f = -1; ch = getchar(); }
	while(isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	return x * f;
}

void solve() {
	ll n = read();
	ll k = read();
	ll res = n * k;

	for(ll l = 1, r; l <= n; l = r + 1) {
		r = k / l ? min(n, k / (k / l)) : n;
		res -= (k / l) * (r - l + 1) * (l + r) / 2;
	}
	printf("%lld\n", res);
}

int main()
{
    int T = 1;
    //scanf("%d", &T);
    for(int i = 1; i <= T; ++i){
        solve();
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值