【蓝桥杯】2017省赛JAVA_B K倍区间 前缀和

题目

 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,否则按无效代码处理。
 


重要概念

使用两个for的递归会超时,为了解决时间复杂度我们使用前缀和。

前缀和:在第i次输入时,保存前i个(包含i)输入数的和。(在本题中保存 和%K即可)

 

求区间[l,r]的和是k的倍数的个数。

求区间和,我们可以通过前缀和来求出。

我们规定sum[i]表示第1个元素到第i个元素的和。

sum[r] - sum[l-1]就是区间[l,r]的和。

区间[l,r]的和是k的倍数即(sum[r] - sum[l-1])%k == 0     即      sum[r]%k == sum[l-1]%k

这样题目就转换为分析统计  sum[x]相同的个数。

(假设sum[r]%k=t(t为任意数),sum[l-1]%k=t,那么两个相减会把余数t抵消掉,从而整除K )

 

注意在最后加上 从0开始的 本身区间就可以整除k的个数

 


public class no10 {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		
		//读入n k
		String inputNK = sc.nextLine();
		int n = Integer.parseInt(inputNK.split(" ")[0]);
		int k = Integer.parseInt(inputNK.split(" ")[1]);
		
		//初始化sum数组,用于保存前缀和%k
		//多出的10是防止溢出
		int[] sum = new int[100010];
		sum[0]=0;
		
		//reminder余数,该数组用于保存第i此输入前相同余数的个数
		int[] reminder = new int[k];
		
		//result保存最后结果
		int result =0;
		
		for(int i=1;i<=n;i++) {
			sum[i]+=(sum[i-1]+sc.nextInt())%k;
			result+=reminder[sum[i]];//与此次前缀和余数相同的个数,就是与此次输入够成可以被K整除的区间个数。
			reminder[sum[i]]+=1;//余数计数加1
		}
		result+=reminder[sum[0]]; //加上了前缀和本身就整除k的个数
		
		System.out.println(result);
		

	}
}

参考:https://blog.csdn.net/qq_34594236/article/details/70845223

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值