[CQOI2007]余数求和
题意描述
给出正整数n和k,计算G(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如G(10, 5)=5 mod 1 + 5 mod 2 + 5 mod 3 + 5 mod 4 + 5 mod 5 …… + 5 mod 10=0+1+2+1+0+5+5+5+5+5=29
样例啊,那我就随便写两个啦
9 3 输出 19
10 5 输出 30
划重点
数据范围n,k<=1e9
咳咳,进入真正重点
首先数据范围就决定了你的暴力已经阵亡
那么你现在肯定满脑子期待着一个O(1)或者O(logn)其实O(根号n)的算法
标准的公式啊代码啊可以移步这里
算是一个友情链接,对面是个手推公式的大佬
不过蒟蒻不太会推公式
但是
咳咳,我会找规律啊
来,先看一个表
10 0
11 1
12 4
13 9
14 2
15 10
16 4
17 15
18 10
19 5
20 0
21 16
22 12
23 8
24 4
25 0
26 22
27 19
28 16
29 13
30 10
31 7
32 4
33 1
34 32
35 30
36 28
37 26
38 24
39 22
40 20
41 18
42 16
43 14
44 12
45 10
46 8
47 6
48 4
49 2
50 0
51 49
52 48
53 47
54 46
55 45
56 44
57 43
58 42
59 41
60 40
61 39
62 38
63 37
64 36
65 35
66 34
67 33
68 32
69 31
70 30
71 29
72 28
73 27
74 26
75 25
76 24
77 23
78 22
79 21
80 20
81 19
82 18
83 17
84 16
85 15
86 14
87 13
88 12
89 11
90 10
91 9
92 8
93 7
94 6
95 5
96 4
97 3
98 2
99 1
100 0
这个表就是100%(1--n)的每一步结果
注意51-100,34-50,26-33
hhh_
等差数列熟不熟悉?
发现在[k/2]+1到k这个区间里,k%i是一个等差数列,公差为1
在[k/3]+1到[k/2]这个区间里,k%i也是一个等差数列,公差为2
在[k/4]+1到[k/3]这个区间里,k%i也是一个等差数列,公差为3
.........
一直到[k/√k]+1到[k/(√k-1)]这个区间里,k%i也是一个等差数列,公差为(√k-1).
剩下的1到[k/√k]的区间直接暴力求解即可.
再特殊处理一下n<k的情况,比如n99,k100可以自己想象一下
那么上代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<cmath>
using namespace std;
long long n,i,k,l,ans;
int main(){
cin>>n>>k;
if(n>=k)
ans=(n-k)*k;
else{
for(i=1;i*i<=k&&i<n;i++){
if(k/i<n){l=k/i;break;}
l=i;
}
l++;
ans=(n-l+1)*(k%n+k/l*(n-l)+k%n)/2;
}
for(i=k/n+1;i*i<=k;i++)
ans+=(k%i+i*(k/i-k/(i+1)-1)+k%i)*(k/i-k/(i+1))/2;
n=k/i;
for(int i=1;i<=n;i++)
ans+=k%i;
cout<<ans;
return 0;
}
完了,不懂的评论问吧