import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
int K = scan.nextInt();
scan.nextLine();
long ans = 0;
int sum = 0;
int[] f = new int[K];
f[0] = 1;
for (int i = 1; i <= N; i++) {
sum += scan.nextInt();
sum %= K;
f[sum] ++;
scan.nextLine();
}
for (int i = 0; i < K ; i++) {
ans += f[i] * (f[i] - 1) / 2;
}
System.out.println(ans);
}
}
这可以
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
int N = scan.nextInt();
int K = scan.nextInt();
scan.nextLine();
long ans = 0;
int sum = 0;
long[] f = new long[K];
f[0] = 1;
for (int i = 1; i <= N; i++) {
sum += scan.nextInt();
sum %= K;
f[sum] ++;
scan.nextLine();
}
for (int i = 0; i < K ; i++) {
ans += f[i] * (f[i] - 1) / 2;
}
System.out.println(ans);
}
}
不可以(差距只在)
long[] f = new long[K];
和
int[] f = new int[K];
输出结果ans必须是long不然数据会溢出
如果最终结果是存储在long
类型的变量中,那么仅在计算f[i] * (f[i] - 1)
这一步导致的溢出,并不会直接影响到最终存储在long
类型的ans
中的结果,因为ans
的累加操作是安全的。
但是,这里的关键点在于,如果f[i]
和f[i] - 1
都是接近int
最大值的整数,它们的乘积确实会超出int
范围,导致在计算该乘积的那一步就发生了溢出。在大多数编程语言中(包括Java),如果两个操作数都是int
类型,即使结果被赋给一个long
类型变量,乘法操作本身仍然会在int
范围内执行,也就是说,先进行int
类型的乘法运算,然后再转换到long
。一旦乘法结果超出了int
的最大表示范围,在转换到long
之前就已经丢失了精度,这就是所谓的溢出。
例如,如果int
的最大值是2^31 - 1,那么两个接近这个值的int
数相乘的结果将会远大于int
所能表示的最大值,此时即便最终存储到的是long
类型变量,乘法操作的结果已经是错误的了。
因此,要确保不发生这样的溢出,需要至少一个乘数是long
类型,这样在进行乘法运算时会以long
的精度来进行,避免中间结果的溢出。这也是为什么将f
数组的类型从int
更改为long
后,第二个代码能够通过测试的原因。