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

来源:互联网 发布:卖家怎么防止淘宝客 编辑:程序博客网 时间:2024/06/10 15:29

我实在是太弱,只好去刷水题了。
首先注意到,对于任意一个1ikki的取值只有O(k)种,并且相同的ki的取值对应的i都是连续的一段区间。所以,先把所有满足条件的区间提取出来。
对于任意一个ki==ki+1,有:
k=iki+kmodi=(i+1)ki+1+kmod(i+1)
x=ki,a=kmodi,则有:
ix+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,...,kr1,kr的值全部相同,则有:
ri=lkmodi=(kmodl)(rl+1)kl(rl)(rl+1)2
这样就很好做了。具体实现见代码。注意,对于任意一个i>kkmodi=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[N], r[N], v[N]; 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;}
原创粉丝点击