本文共 2649 字,大约阅读时间需要 8 分钟。
标题: 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 45
程序应该输出:
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 stub int 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); }}
参考了大神的代码
下面这个代码非常巧妙,将前缀和保存到数组中,减少每次不必要的嵌套计算,而同时%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]); }}
转载地址:http://mrjaf.baihongyu.com/