我正在尝试编程问题,声明是 如果我们列出10以下的所有自然数是3或5的倍数,我们得到3,5,6和9.这些倍数的总和是23.像这样我们必须找到'的倍数之和。吨'测试用例' n'每个值,我试图找到解决方案,我的代码是
import java.io.*;
import java.util.*;
import java.text.*;
import java.math.*;
import java.util.regex.*;
public class Solution {
public static void main(String[] args) {
long t,n,sum;
Scanner in=new Scanner(System.in);
t=in.nextLong();
for(int i=0;i<t;i++)
{
sum=0;
n=in.nextLong();
long l3=0,l5=0,l15=0;
for(int j=3;j>0;j--)
if((n-j)%3==0&&j<n)
{
l3=n-j;
break;
}
for(int j=5;j>0;j--)
if((n-j)%5==0&&j<n)
{
l5=n-j;
break;
}
for(int j=15;j>0;j--)
if((n-j)%15==0&&j<n)
{
l15=n-j;
break;
}
sum+=(float)(((float)l3/(float)3)/(float)2)*(float)(l3+3);
sum+=(float)(((float)l5/(float)5)/(float)2)*(float)(l5+5);
sum-=(float)(((float)l15/(float)15)/(float)2)*(float)(l15+15);
System.out.println(sum);
}
}
}
我提供的输入是,
12
10
11
12
13
1000
1001
1002
1003
100000000
100000001
100000002
100000003
这里有12个测试用例的数量。
我得到的输出是
23
33
33
45
233168
234168
234168
235170
2333333593784320
2333333593784320
2333333593784320
2333333593784320
这里的问题是对于测试用例10,11,12,13,1000,1001,1002,1003中的值,答案是正确的,但输出对于剩余的较大输入是错误的。我找不到我错过的东西。你能帮我解释一下为什么我会得到这种错误的结果以及如何纠正它。
答案 0 :(得分:1)
如果没有对代码进行更深入的分析,我猜测问题就是你使用浮点数,它的值范围非常短。你可以尝试双倍吗?不确定答案是什么,但至少你会得到不同的结果(我刚试过)
答案 1 :(得分:1)
对于这样的任务,解决方案看起来太复杂了。我不明白你为什么要在最后执行分工。您可以尝试以下代码:
int t = <some number> // the upper bound
int[] dividers = [...] // those are divisors against which we have to test
long sum = 0;
// check all the number up the bound
for (int number = 1; number < t; number++) {
for (int i = 0; i < dividers.length; i++) {
if (number % dividers[i] == 0) {
// the number is divisible without remainder -> add it to the sum
sum += number;
break;
}
}
}
这个想法是迭代你要检查的所有数字,看看它们是否可以被一些N分频器整除。如果找到一个数字,则将其添加到总和中并继续下一个数字。
修改强> 在OP的澄清之后,我提出了另一种方法来做到这一点。
int t = <some number> // the upper bound
int dividers = [3, 5];
int dividerProduct = dividers[0] * dividers[1];
long sum = calculateSumForDivider(dividers[0], t) + calculateSumForDivider(dividers[1], t) - calculateSumForDivider(dividerProduct, t);
public static int calculateSumForDivider(int divider, int number) {
int n = number / divider;
return divider * n * (n + 1) / 2;
}
这一切背后的逻辑是什么? 通过除以目标数,我们可以计算分配器在目标中“适合”的次数。这也是区间[1,数字]中可被除法器整除的数字数。我们来看一个例子:
t = 10, divider = 3
10 / 3 = 3, so they are 3 numbers in the interval [1, 10], divisible by 3
the numbers are: 1 * 3, 2 * 3, 3 * 3
if we calculate the sum we get 1 * 3 + 2 * 3 + 3 * 3 = 3 * (1 + 2 + 3) = 18
analogically, for = 10, divider = 5
10 / 5 = 2
1 * 5 + 2 * 5 = 5 * (1 + 2) = 15
作为结论,我们总结了以下公式:
sum = divider * n * (n + 1) / 2
其中n
是除法的结果。
这里的问题是,可以被3和5整除的数字(换句话说可被15整除)将被加到两次总和中。为了纠正这个问题,我们使用与上面相同的公式来计算它们的总和,并从得到的总和中减去它,得到结果。
此解决方案仅适用于2个分隔符,因为多个将多次添加到总和的数字将以指数方式增长。 F.E.如果我们想要分为3,4或5,我们将需要照顾12,15,20,60等。
如果两个分频器是另一个分频器的功率,如3和9,这也行不通。在这种情况下,我们只需要可被3整除的数字。
答案 2 :(得分:1)
使用BigDecimal和BigInteger可以获得更高的精度和更大的数字:
package test;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.Scanner;
public class Solution {
public static void main(String[] args) {
long t,n;
BigInteger sum;
Scanner in=new Scanner(System.in);
t=in.nextLong();
for(int i=0;i<t;i++)
{
sum = BigInteger.ZERO;
n=in.nextLong();
long l3=0,l5=0,l15=0;
for(int j=3;j>0;j--)
if((n-j)%3==0&&j<n)
{
l3=n-j;
break;
}
for(int j=5;j>0;j--)
if((n-j)%5==0&&j<n)
{
l5=n-j;
break;
}
for(int j=15;j>0;j--)
if((n-j)%15==0&&j<n)
{
l15=n-j;
break;
}
BigDecimal x = BigDecimal.valueOf(l3)
.divide(BigDecimal.valueOf(6))
.multiply(BigDecimal.valueOf(l3+3));
sum=sum.add(x.toBigIntegerExact());
x = BigDecimal.valueOf(l5)
.divide(BigDecimal.valueOf(10))
.multiply(BigDecimal.valueOf(l5+5));
sum=sum.add(x.toBigIntegerExact());
x = BigDecimal.valueOf(l15)
.divide(BigDecimal.valueOf(30))
.multiply(BigDecimal.valueOf(l15+15));
sum=sum.subtract(x.toBigIntegerExact());
System.out.println(sum);
}
}
}
答案 3 :(得分:0)
我不确定你的算法,因为最简单的算法应该是:
sum=0;
n=100100000;
for(int j=1;j<n;j++)
if(j%3==0 || j%5==0)
{
sum+=j;
}
System.out.println(sum);
System.out.println(n*n);
为了更好地了解结果应该是什么,它总是小于n*n
。
我找到的输出是:
2338002249916668
10020010000000000
因此,如果你的结果小于n*n
,如果你确定你的算法,那么它们是正确的。