Codeforces - Educational Codeforces Round 5 - E. Sum of Remainder

题目链接:http://codeforces.com/contest/616/problem/E

题目大意:给定整数n,m(1≤n,m≤1013), 求(n mod 1 + n mod 2 + ... + n mod m)的值(mod Pt = 1e9 + 7)。

思路:这题一看是看觉得题意简洁,通过人数不多一定是一道用到各种定理的碉堡数论题。后来仔细想了一下发现是乱搞…

首先通过观察数据范围,结合数论题的复杂度传统考虑O(√n)算法。

把n拆解,可以任意写成很多种n = px + r 的形式,而p, x中必有一个≤√n,首先对于[1,√n]的x暴力处理n % x,而当x > √n的时候,就出现了一个[1, √n]的p,对应一段连续的x的情况,同样r也是对应的。如果能够快速批处理出这些r的和,那么就能通过1 - √n枚举p来搞定x∈[√n, +∞]的情况。通过观察,对于任何一个p对应的连续的x区间,r都成首项为n - (n / p) * p, 公差为p,项数为n / p - n / (p + 1)的等差数列前n项和,因此带入公式可O(1)得解。 先枚举p去做代码比较好些,直到n / p < √n,把成块的x处理结束,剩下谁就直接从1到那个值暴力枚举计算比较容易写。

当m > n的时候把m变成n,答案初始为n * (m - n) 即可。值得注意的是m < n的时候,要注意从p等于多少开始能覆盖到m,那个边界的x区间中,r的首项为n % m。

题目要求% Pt, 这一点卡的很严,注意n % m之后还要再 % Pt,而且中间计算的过程中每一步运算都要%,防止爆long long。

 1 #include <cstdio>
 2 #include <cstdlib>
 3 #include <cstring>
 4 #include <cmath>
 5 #include <algorithm>
 6 using namespace std;
 7 typedef long long LL;
 8 
 9 const LL Pt = 1e9 + 7;
10 LL n, m, d1, d2, a, k, ans, pos, ans1;
11 
12 int main()
13 {
14     scanf("%I64d%I64d", &n, &m);
15     if (m > n) ans = ((n % Pt) * ((m - n) % Pt)) % Pt, m = n;
16     bool flag = false;
17     for (LL i = 2; i <= n; i++)
18     {
19         d1 = n / i; d2 = n / (i - 1);
20         if (d1 < m && !flag) 
21         {
22             flag = true;
23             a = (n % m) % Pt;
24             k = (m - d1) % Pt;
25             a = ((a * k) % Pt + (((k * (k - 1) / 2) % Pt) * (i - 1)) % Pt) % Pt;
26             ans = (ans + a) % Pt;
27             continue;
28         }
29         if (flag)
30         {
31             a = (n - d2 * (i - 1)) % Pt;
32             k = (d2 - d1) % Pt;
33             a = ((a * k) % Pt + (((k * (k - 1) / 2) % Pt) * (i - 1)) % Pt) % Pt;
34             ans = (ans + a) % Pt;
35         }
36         if (d1 <= sqrt(n)) {pos = d1; break;}
37     }
38     for (LL i = 1; i <= min(pos, m); i++) ans = (ans + n % i) % Pt;
39     printf("%I64d\n", ans);
40 }
View Code

 

转载于:https://www.cnblogs.com/ChopsticksAN/p/5148646.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值