湘潭 A simple problem
A simple problem |
||
Accepted : 30 | Submit : 303 | |
Time Limit : 15000 MS | Memory Limit : 655360 KB |
Problem DescriptionThere is a simple problem. Given a number N. you are going to calculate N%1+N%2+N%3+...+N%N. InputFirst line contains an integer T, there are T(1≤T≤50) cases. For each case T. The length N(1≤N≤1012). OutputOutput case number first, then the answer. Sample Input1 5 Sample OutputCase 1: 4 Sourcedaizhenyang |
学习莫比乌斯反演的时候,用到了一些常数的优化。用这样的方法能够解决这一道题。
当然找规律也是可以做的,其实都是一样的,只不过从一个归纳的角度去看这一道题。
思路:先举个例子。
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 MBSubmit: 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
Sample Output
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 }