蓝桥杯 k倍区间 Java 实现

题目: 题目OJ
在这里插入图片描述
这个题想还是挺好想的,区间问题嘛,一看就是前缀和嘛 一写就T
因为数据1e5 很明显我们直接两重循环来判断绝对T的
所以我们可以把这个问题分成两类问题来解决,首先当然是用a[i] 来表示前i个数之和
(1)如果a[i] % k == 0 这个不用说 ans++ 即可
(2)除去第一种情况,剩下就是要减的了,就是要算2个区间的差值了,这里我们可以来看我们需要找的是 (a[i] - a[j])% k == 0 我们就可以看成 a[i] % k == a[j] % k 也就是说只要这两个数%k 的值相等 他们就绝对可以组成一个 K倍区间,我们这里就可以在来一个数组 设为cnt[]
cnt[i] : %k 余数的区间个数 这样我们每次扫描到一个前缀和的时候我们只需要将它%k 然后
ans += cnt[a[i]] 即可,这个复杂度就大大减低啦 题目OJ
例如:
数组为 1 2 3 4 5 k:2
前缀和为 1 3 6 10 15
1 : a[i] % k == 1 ans += cnt[1] = 0 cnt[1]++
3 : a[i] % k == 1 ans += cnt[1] = 1 cnt[1]++
6 : 先判断第一种情况 ans++ (ans = 2) a[i] % k == 0 ans += cnt[0] = 2 cnt[0] ++
10 : 先判断第一种情况 ans++ (ans = 3) a[i] % k == 0 ans += cnt[0] = 4 cnt[0]++
15: a[i] % k == 1 ans += cnt[1] = 6 cnt[0]++

代码

import java.io.*;
public class P7165k倍区间 {
	/*
	 * 用a[i]表示前i个数的和
	 * 一个区间是k的倍数
	 * 二种情况
	 * (1)a[i]是k的倍数 1~i 和为k的倍数 这个时候 ans++
	 * (2)a[i]-a[j]是k的倍数 i~j 和为k的倍数 这个时候我们看成 a[i]%k == a[j]%k
	 *  所以我们只需要每次将每一个前缀和都%k 加入到余数的数组 cnt[t]:表示当前余数为t的区间段有cnt[t]个 ans+=cnt[t]就好了
	 */
	static int N = 100010;
	static int a[] = new int[N];
	static int cnt[] = new int[N];
	static int n;
	static int k;
	static long ans = 0;
	public static void main(String[] args) throws IOException{
		StreamTokenizer re = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
		PrintWriter pr = new PrintWriter(new OutputStreamWriter(System.out));
		re.nextToken(); n = (int)re.nval;
		re.nextToken(); k = (int)re.nval;
		for(int i = 1;i <= n;i++){
			re.nextToken();
			a[i] = (int)re.nval;
			a[i] = (a[i]+a[i-1])%k;
			if(a[i] == 0)
				ans++;
			ans += cnt[a[i]];
			cnt[a[i]]++;
		}
		pr.println(ans);
		pr.flush();
	}
}
发布了32 篇原创文章 · 获赞 5 · 访问量 862

猜你喜欢

转载自blog.csdn.net/shizhuba/article/details/105301239