博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
蓝桥杯第八届省赛JAVA真题----k倍区间
阅读量:2027 次
发布时间:2019-04-28

本文共 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  
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 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/

你可能感兴趣的文章
八大排序算法
查看>>
C++ 11
查看>>
Spring @Configuration 和 @Component 区别
查看>>
JVM内存模型
查看>>
syslog日志记录
查看>>
Linux下的动态库.so
查看>>
jQuery解决input中placeholder值在ie中无法支持的问题
查看>>
一文深度揭秘Redis的磁盘持久化机制
查看>>
java是编译型还是解释型语言
查看>>
Spring的BeanUtils的copyProperties方法需要注意的点
查看>>
NotePad 常用快捷键总结
查看>>
Notepad++如何让打开的文件排在左边菜单栏
查看>>
File类的常用方法【二】
查看>>
为什么说栈的速度快,堆的速度慢?栈和堆的区别是什么?
查看>>
微信支付兴起,万亿级用户交易记录存储的挑战
查看>>
Java nio 实现socket异步通信
查看>>
商品秒杀系统设计思路
查看>>
Java自带的JVM性能监控及调优工具(jps、jinfo、jstat、jmap、javap)使用介绍
查看>>
方法回调/钩子
查看>>
Java中常用缓存Cache机制的实现
查看>>