题目链接 [CQOI2007]余数求和
首先,题目让我们求这样一个东西:
然后,取模操作,可以看成
对原式进行化简,可以得到
其中可以O(1)的求解得到。
然后就到了求解
我们都知道一个数,在做整除取整操作的时候,是有很多重复的值的,譬如说到最后,就有很多个“1”是一个道理。
所以,用到一个知识点叫做“除法分块”。
除法分块的要求,就是对于所有除得值为相同的元素,就要一起处理了,譬如说K=11的时候:
i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | >11 |
val | 11 | 5 | 3 | 2 | 2 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
那么,可以通过不断的向后挪动找,将val值相同的就集体处理了。
处理的循序就是:
- 1~1: 11
- 2~2: 5
- 3~3: 3
- 4~5: 2
- 6~11: 1
- end
而这样的处理方法的时间复杂度只有
所以,在这道数据范围只有1e9的题目中,我们就可以利用除法分块来解决这个问题了。
复杂度证明
假设我们需要枚举前个,那么设当前位为,则前一位是
想要证明
利用反证法,
又有
所以不成立,故原式成立,只需要枚举至第位,后面是逐段连续的递减的。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define eps 1e-8
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
ll N, K, ans;
int main()
{
scanf("%lld%lld", &N, &K);
ans = N * K;
ll l = 1, r, val;
while(true)
{
if(l > N || l > K) break;
val = K / l;
r = K / val;
r = min(r, N);
ans -= val * (r - l + 1LL) * (l + r) / 2LL;
l = r + 1;
}
printf("%lld\n", ans);
return 0;
}