湘潭 A simple problem

A simple problem

Accepted : 30 Submit : 303
Time Limit : 15000 MS Memory Limit : 655360 KB

 

Problem Description

There is a simple problem. Given a number N. you are going to calculate N%1+N%2+N%3+...+N%N.

Input

First line contains an integer T, there are T(1≤T≤50) cases. For each case T. The length N(1≤N≤1012).

Output

Output case number first, then the answer.

Sample Input
1
5

Sample Output
Case 1: 4


Source

daizhenyang

 

 学习莫比乌斯反演的时候,用到了一些常数的优化。用这样的方法能够解决这一道题。

 当然找规律也是可以做的,其实都是一样的,只不过从一个归纳的角度去看这一道题。

思路:先举个例子。

15%1 = 0 等差数列!!只不过只有一个数而已么

15%2 = 1 等差数列!!只不过只有一个数而已么

15%3 = 2 等差数列!!只不过只有一个数而已么

15%4 = 3   15%5=0 等差数列!!

15%6 = 3   15%7=1 等差数列!!

15%8 = 7    15%9=6   15%10=5.....  15%14=1   15%15=0 等差数列!!

观察是可以得到的,其实这个是另一个的一种转化。就是/

如果15/i == 15/(i+k) 那么这k个值都是相同。显然 。

比如,拿最后一组来说15/8 == 15/(8+7),确实是。

那么我们能用到莫比乌斯反演里讲的优化,求区间的上限就可以了。i - 区间上限,就是一个等差数列。

上限的值为(n/(n/i)),解决。

具体见代码:因为在求和过程中会溢出,所以我用java了。

 1// package ttMain;
 2 
 3 import java.math.BigInteger;
 4 import java.util.Scanner;
 5 
 6 public class Main{
 7 
 8     public static void main(String[] args) {
 9         Scanner cin = new Scanner(System.in);
10         int T = cin.nextInt();
11         for(int t=1;t<=T;t++)
12         {
13             long n = cin.nextInt();
14             System.out.println("Case "+t+":"+" "+solve(n));
15         }
16     }
17     
18     private static BigInteger solve(long n) {
19         
20         BigInteger sum = BigInteger.ZERO;
21         long d=0 ;
22         /**
23          * 看起来是一个for,10^12,其实不是的。是sqrt(n).
24          * n/i == n/(k+i) 这里节省了很多的.
25          */
26         for(long i=1,la = 0;i<=n;i=la+1){
27             la = n/(n/i);
28             if(la==i){ //如果只有一个元素
29                 sum = sum.add(BigInteger.valueOf(n%i));
30                 continue;
31             }
32             //否则算出d
33             d = n%(i+1) - n%i;
34             sum = sum.add(GetSum(n%i,la-i+1,d));
35         }
36         return sum;
37     }
38 
39     private static BigInteger GetSum(long a1, long n,long d) {
40         /**
41          * 求等差数列前n项和
42          */
43         BigInteger an = BigInteger.ZERO;
44         an = BigInteger.valueOf(a1).
45             add(BigInteger.valueOf(n-1).multiply(BigInteger.valueOf(d)));
46         BigInteger sumn = BigInteger.valueOf(a1).add(an);
47         sumn = sumn.multiply(BigInteger.valueOf(n)).divide(BigInteger.valueOf(2));
48         return sumn;
49     }
50     
51 }

 

更为一般的情况:

1257: [CQOI2007]余数之和sum

Time Limit: 5 Sec  Memory Limit: 162 MB
Submit: 1743  Solved: 810
[Submit][Status]

Description

给出正整数n和k,计算j(n, k)=k mod 1 + k mod 2 + k mod 3 + … + k mod n的值,其中k mod i表示k除以i的余数。例如j(5, 3)=3 mod 1 + 3 mod 2 + 3 mod 3 + 3 mod 4 + 3 mod 5=0+1+0+3+3=7

Input

输入仅一行,包含两个整数n, k。

Output

输出仅一行,即j(n, k)。

Sample Input

5 3

Sample Output

7

HINT

 

50%的数据满足:1<=n, k<=1000 100%的数据满足:1<=n ,k<=10^9

 

Source

 
源代码改一下就可以
 1 //package ttMain;
 2 
 3 import java.math.BigInteger;
 4 import java.util.Scanner;
 5 
 6 public class Main{
 7 
 8     public static void main(String[] args) {
 9         
10         Scanner cin = new Scanner(System.in);
11         long n = cin.nextLong();
12         long k = cin.nextLong();
13         BigInteger sum = BigInteger.ZERO;
14         if(k<n){
15             BigInteger tmpSum = BigInteger.valueOf(k);
16             tmpSum = tmpSum.multiply(BigInteger.valueOf(n-k));
17             sum = sum.add(tmpSum);
18 //            System.out.println(tmpSum);
19         }
20         sum = sum.add(solve(k,n));
21         System.out.println(sum);
22     }
23     
24     private static BigInteger solve(long k,long n) {
25         
26         BigInteger sum = BigInteger.ZERO;
27         long d=0 ;
28         boolean flag = false;
29         /**
30          * 看起来是一个for,10^12,其实不是的。是sqrt(k).
31          * k/i == k/(k+i) 这里节省了很多的.
32          */
33         for(long i=1,la = 0;i<=k;i=la+1){
34             if(flag) break;
35             la = k/(k/i);
36             if(k>n && la>=n) {
37                 la = n;
38                 flag = true;
39             }
40             if(la==i){ //如果只有一个元素
41                 sum = sum.add(BigInteger.valueOf(k%i));
42                 continue;
43             }
44             //否则算出d
45             d = k%(i+1) - k%i;
46             sum = sum.add(GetSum(k%i,la-i+1,d));
47         }
48         return sum;
49     }
50 
51     private static BigInteger GetSum(long a1, long n,long d) {
52         /**
53          * 求等差数列前n项和
54          */
55         BigInteger an = BigInteger.ZERO;
56         an = BigInteger.valueOf(a1).
57             add(BigInteger.valueOf(n-1).multiply(BigInteger.valueOf(d)));
58         BigInteger sumn = BigInteger.valueOf(a1).add(an);
59         sumn = sumn.multiply(BigInteger.valueOf(n)).divide(BigInteger.valueOf(2));
60         return sumn;
61     }
62     
63 }

 

转载于:https://www.cnblogs.com/tom987690183/p/3775784.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值