Algorithm 在一个范围内查找mod操作的总和
如果我们有两个数字,比如说Algorithm 在一个范围内查找mod操作的总和,algorithm,math,Algorithm,Math,如果我们有两个数字,比如说a和b,那么我们如何找到b%i的和的值,其中i的范围是1到a? 一种方法是迭代从1到a的所有值,但是有没有有效的方法? (比O(n)好?) 例如:如果a=4,b=5,则要求ans=5%1+5%2+5%3+5%4=4 谢谢。对于i>b,我们有b%i==b,因此可以在恒定时间内轻松计算出部分总和((a-b)*b,如果a>=b,则0) 对于i的部分,仅在a b so\sum_{i=b}^a=a(a-1)/2-b(b-1)/2的情况下找到一个解就足够了。 #include &l
a和b
,那么我们如何找到b%i的和的值,其中i的范围是1到a
?
一种方法是迭代从1到a的所有值,但是有没有有效的方法?
(比O(n)好?)
例如:如果a=4,b=5,则要求ans=5%1+5%2+5%3+5%4=4
谢谢。对于
i>b
,我们有b%i==b
,因此可以在恒定时间内轻松计算出部分总和((a-b)*b
,如果a>=b
,则0)
对于
i的部分,仅在a b so\sum_{i=b}^a=a(a-1)/2-b(b-1)/2的情况下找到一个解就足够了。
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
unsigned long long usqrt(unsigned long long n);
unsigned long long modSum(unsigned long long a, unsigned long long b);
int main(int argc, char *argv[]){
unsigned long long a, b;
b = (argc > 1) ? strtoull(argv[argc-1],NULL,0) : 10000;
a = (argc > 2) ? strtoull(argv[1],NULL,0) : b;
printf("Sum of moduli %llu %% i for 1 <= i <= %llu: %llu\n",b,a,modSum(a,b));
return EXIT_SUCCESS;
}
unsigned long long usqrt(unsigned long long n){
unsigned long long r = (unsigned long long)sqrt(n);
while(r*r > n) --r;
while(r*(r+2) < n) ++r;
return r;
}
unsigned long long modSum(unsigned long long a, unsigned long long b){
if (a < 2 || b == 0){
return 0;
}
unsigned long long sum = 0, i, l, u, r = usqrt(b);
if (b < a){
sum += (a-b)*b;
}
u = (a < r) ? a : r;
for(i = 2; i <= u; ++i){
sum += b%i;
}
if (r < a){
u = (a < b) ? a : (b-1);
i = b/u;
l = b/(i+1);
do{
sum += (u-l)*b;
sum -= i*(u-l)*(u+l+1)/2;
++i;
u = l;
l = b/(i+1);
}while(u > r);
}
return sum;
}