您的位置:首页 > 其它

[BZOJ1257][CQOI2007]余数求和(数论)

2017-09-03 00:41 211 查看
我实在是太弱,只好去刷水题了。

首先注意到,对于任意一个1≤i≤k,⌊ki⌋的取值只有O(k√)种,并且相同的⌊ki⌋的取值对应的i都是连续的一段区间。所以,先把所有满足条件的区间提取出来。

对于任意一个⌊ki⌋==⌊ki+1⌋,有:

k=i∗⌊ki⌋+kmodi=(i+1)∗⌊ki+1⌋+kmod(i+1)

设x=⌊ki⌋,a=kmodi,则有:

i∗x+a=(i+1)∗x+kmod(i+1)

化简得a=x+kmod(i+1)。

即对于任意一个⌊ki⌋==⌊ki+1⌋,有kmodi=kmod(i+1)+⌊ki⌋。

也就是说,对于一段区间[l,r],如果⌊kl⌋,⌊kl+1⌋,...,⌊kr−1⌋,⌊kr⌋的值全部相同,则有:

∑ri=lkmodi=(kmodl)∗(r−l+1)−⌊kl⌋∗(r−l)∗(r−l+1)2。

这样就很好做了。具体实现见代码。注意,对于任意一个i>k,kmodi=k。

代码:

#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
int res = 0; bool bo = 0; char c;
while (((c = getchar()) < '0' || c > '9') && c != '-');
if (c == '-') bo = 1; else res = c - 48;
while ((c = getchar()) >= '0' && c <= '9')
res = (res << 3) + (res << 1) + (c - 48);
return bo ? ~res + 1 : res;
}
typedef long long ll;
const int N = 1e5 + 5;
int n, k, l
, r
, v
; ll ans;
int main() {
int i, tot = 0; n = read(); k = read();
for (i = 1; i <= k;) {
v[++tot] = k / i;
l[tot] = i; r[tot] = k / v[tot];
i = r[tot] + 1;
}
for (i = 1; i <= tot; i++) {
int len = min(n, r[i]) - l[i], t = k % l[i];
ans += 1ll * t * (len + 1) - 1ll * v[i] * len * (len + 1) / 2;
if (len == n) break;
}
if (n > k) ans += 1ll * (n - k) * k; cout << ans << endl;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: