标题: k倍区间
给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,我们就称这个区间[i, j]是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语句。不要使用jdk1.7及以上版本的特性。
主类的名字必须是:Main,否则按无效代码处理。
思路:题目中的例子6种情况为:2 4 123 345 1234 2345 。这不是一道难度很大的题,至少在理解上是的,但是一般思路做出来的方法肯定是得不了满分的,这可能也是蓝桥杯的另一种“套路”吧,将题目的理解变简单,但是要求变困难。这里就更能体现出算法的重要性。
一开始上来就这直接暴力求了,结果做完时间复杂度为O(n^3),严重超时,甚至还有一个非常不必要的嵌套。
import java.util.Scanner;
public class Main {static int n = 0;static int k = 0;static int[] a;static int cnt = 0;public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();k = in.nextInt();a = new int[n+1];for (int i = 0; i < n; i++) {a[i] = in.nextInt();}for (int i = 0; i < n; i++) {for (int j = i; j < n; j++) {if (sum(i, j)% k == 0) {cnt++;}}}System.out.println(cnt);}private static int sum(int i, int j) {// TODO Auto-generated method stubint s = 0;for (int k = i; k <= j; k++) {s += a[k];}return s;}
}
接下来,消除嵌套之后,时间复杂度降到了O(n^2),但实际上这个题目必须达到线性O(n)才能得到满分。
import java.util.Scanner;
public class Main {static int n = 0;static int k = 0;static int[] a;static int cnt = 0;static int sum;public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();k = in.nextInt();a = new int[n+1];for (int i = 0; i < n; i++) {a[i] = in.nextInt();}for (int i = 0; i < n; i++) {sum = 0;for (int j = i; j < n; j++) {sum += a[k];if (sum % k == 0) {cnt++;}}}System.out.println(cnt);}
}
参考了大神的代码2017第八届蓝桥杯C/C++ B组省赛题解
下面这个代码非常巧妙,将前缀和保存到数组中,减少每次不必要的嵌套计算,而同时%k会产生两种结果,0或者小于k,这相当于直接记录了符合(%k = 0)与不符合(%k < k)两种情况。根据(sum[r] - sum[l-1]) % k == 0 就可以判断一个区间[l, r]是符合约束区间。但是这样会使用双重循环,时间复杂度为O(n^2),这样并没有完全把这种算法的好处利用到,而且我们的目的是计算个数,而非要输出所有的k倍区间。
根据上面的式子我们可以看出只要区间两端点的前缀和%k相等,那么这段区间就符合约束,所以我们只需每次使sum加上与当前位置前缀和%k相等的数量(即bk[a[i]]++)就行。
(注意最后的结果还要加上前缀和%k=0的值,这是它自身到1的区间,也符合约束。)
import java.util.Scanner;
public class Main {static int n = 0;static int k = 0;static int sum;static int[] a;static int[] bk;static int cnt = 0;public static void main(String[] args) {Scanner in = new Scanner(System.in);n = in.nextInt();k = in.nextInt();a = new int[n+1];bk = new int[n+1];for (int i = 0; i < n; i++) {a[i] = in.nextInt();}a[0] %= k;for (int i = 1; i < n; i++) {a[i] = (a[i] + a[i-1]) % k;}for (int i = 0; i < n; i++) {sum += (bk[a[i]]++);}System.out.println(sum + " "+ bk[0]);}
}