2017–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
前缀和是区间的利器
N^2解决10的4次方的规模
前5和前缀和余上k
作用
同余做差一定是模的倍数
s[0]=0初始化是必要的的
java中读文件:
拷文件之后还要加入异常处理就是上面的
package 第八届;
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class K倍区间1 {
static int n,k;
static int[] a;
static int[] s;//前缀和
//同余的统计,java中要改成Map,而java中只能存对象,不可以存数据的类型
static Map<Integer,Long> cnt=new HashMap<Integer,Long>();
public static void main(String[] args) {
// TODO Auto-generated method stub
Scanner sc=new Scanner(System.in);
n=sc.nextInt();
k=sc.nextInt();
a=new int[n+1];
s=new int[n+1];
s[0]=0;
cnt.put(0,1l);
for(int i=1;i<=n;i++){
a[i]=sc.nextInt();
s[i]=(s[i-1]+a[i])%k;
if(cnt.get(s[i])==null){
cnt.put(s[i],1l);//计数为1
}else{
cnt.put(s[i],cnt.get(s[i])+1);//计数加1
}
}
long ans=0;
for(int i=0;i<k;i++){//余数必然在0~k-1之间
//c++里面可能取出cnt为0,C里面默认找不到就为0
Long cntI=cnt.get(i);
if(cntI==null)cntI=0l;
//防止溢出,强制转化
ans +=cnt.get(i)*(cnt.get(i)-1)/2;//例如所有前缀和中%k=3的有3个,呢么他们任意选2可得一个k倍区间,C32=3*2/2
}
System.out.println(ans);
}
}