首页 > 代码库 > NYOJ 508 余数求和 (数论问题)

NYOJ 508 余数求和 (数论问题)

题目描述 

http://acm.nyist.net/JudgeOnline/problem.php?pid=508

给你两个数n,k,请求出技术分享的值。

输入
每行两个数n, k(1 <= n, k <= 10^9).
输出
输出和,每个结果占一行。
样例输入
5 4
5 3
样例输出
5
7

题目分析:

对于此题不能直接进行暴力,数值大,只能用sqrt(n)的算法,首先计算n%i的余数和,i=1~n;注意到:n%i=n/i*i;

因此我们可以模拟从i=1~sqrt(n);sum+=n%i;对于i对应的j=n/i,可以知道(n/i~n/i+1)==d;对与这组数,计算得到

s1=((n/i-n/(i+1))*n)-d*(n/(i+1)+1+......+n/i);sum+=s1;直到循环结束,就得到n%i的余数和,我们用ModSum(n)。

现在我们求k%i的余数和,i=1~n;进行分析k和n即可,

一、k<n  res=ModSum(k)+(n-k)*k;注:当n>k时,k%n==k

二、k=n  res=ModSum(k)

三、k>n  res=ModSum(k); { for(int i=n+1;i<=n;i++)

res-=k%i;//减去多计算的值即可。

}


AC代码:

 
/**
 *1、ModSum1():O(n)
 *2、ModSum2():O(sqrt(n))
 *1   2   3   4
 *16  8   5   4
 *  1   2   3
 */
#include<iostream>
#include<cstdio>
#include<map>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<vector>
#include<stack>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<cmath>
#define LL long long
#define MOD 1000000007
using namespace std;
LL ModSum1(LL n){
    LL t=(n+1)/2-1;
    LL sum=t*(t+1)/2;
    for(LL i=1;i<=n/2;i++){
        sum+=n-(n/i*i);
    }
    return sum;
}

LL ModSum2(LL n,LL k){
    LL sum=0,n1=n;
    n=k;
    LL tem=sqrt(n);
    for(LL i=1;i<=tem;i++){
        if(n/i==i){
            sum+=n-n/i*i;
            continue;
        }
        sum+=n-n/i*i;
        sum=sum;
        //cout<<n/(i+1)<<" "<<n/i<<endl;
        LL tt=n*(n/i-(n/(i+1)))-i*((n/i+(n/(i+1))+1)*(n/i-(n/(i+1)))/2);
        //sum=(sum+(tt%MOD*i%MOD)%MOD)%MOD;
        sum=(sum+tt);
    }
    //cout<<n1<<k<<endl;
    if(k<=n1){
        sum+=(n1-k)*k;
    }
    else {
        for(LL i=n1+1;i<=k;i++){
            sum-=k%i;
        }

    }
    return sum;
}
int main()
{
	long long n,k;
	while(cin>>n>>k){
        //LL sum1=ModSum1(n);
        LL sum2;

        sum2=ModSum2(n,k);


        cout<<sum2<<endl;
	}
	return 0;
}
        



NYOJ 508 余数求和 (数论问题)