蓝桥杯真题 k倍区间
考点:
- 利用前缀和求子列和
- 同余作差是模的倍数
题目概要
你能求出数列中总共有多少个K倍区间吗?
输入 第一行包含两个整数N和K。(1 <= N, K <= 100000) 以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)
输出 输出一个整数,代表K倍区间的数目。
例如,
输入: 5 2 1 2 3 4 5
程序应该输出: 6
资源约定: 峰值内存消耗(含虚拟机) < 256M CPU消耗 < 2000ms
子列和问题的解法:前缀和(静态数据)、树状数组、区间数
给出代码
package demo;
import java.util.Scanner;
public class Main {
public static int k, n;
public static long ans = 0;
public static long[] a = new long[100010];
public static long[] s = new long[100010];
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
k = in.nextInt();
s[0] = 0;
for (int i = 1; i <= n; i++) {
a[i] = in.nextLong();
s[i] = s[i - 1] + a[i];
}
//枚举i,j,求得两者之间的区间和:s[j]-s[i-1],区间和可以是一个数
for (int i = 1; i <= n; i++) {
for (int j = i; j <= n; j++) {
if ((s[j] - s[i - 1]) % k == 0)
ans++;
}
}
System.out.println(ans);
}
}
但这样的代码只能解决10的4次方规模的问题,而题目中给的是10的5次方。那么要对代码进行进一步的优化。
同余作差,一定是模的倍数,在余数相同的一堆里,任取两个,就可以相减得到子列和(C32组合数),最后要加上mod[0],因为余0的数有两种考虑模式:第一种是任选两个相减,第二种是这个数之间一个人做一个子列
优化后的代码
package demo;
import java.util.Scanner;
public class Main {
public static int k, n;
public static long ans = 0;
public static long[] a = new long[100010//这里可以不用开那么大的预空间
public static long[] s = new long[100010];//用的时候再开也可以的
public static void main(String args[]) {
Scanner in = new Scanner(System.in);
n = in.nextInt();
k = in.nextInt();
long[] mod = new long[k];
s[0] = 0;
for (int i = 1; i <= n; i++) {
a[i] = in.nextLong();
s[i] = (s[i - 1] + a[i]) % k;
mod[(int) s[i]]++;
}
for (int i = 0; i < k; i++) {
// System.out.println("mod" + i + " = " + mod[i]);
ans = ans + mod[i] * (mod[i] - 1) / 2;
}
System.out.println(ans + mod[0]); // 所有能直接被k整除的都可以直接拿出来做一个区间
}
}

浙公网安备 33010602011771号