目录
🍋题目描述
给定一个长度为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
🍋解题思路
🍊🍊思路一
暴力破解:
用s[i]存取前i项和。之后双指针,进行扫描。
不过这样运行超时了,练习系统中测得只有28分。
🍊🍊思路二
数学思维:
把前i项和s[i],进行对k的取余,对取余结果相等的任两个前n项和都能是k倍区间
🍋源代码
🍊🍊思路一代码
import java.util.Scanner;
public class Main
{
static int n,k;
static int[]a;
static int[]s;
public static void main(String[] args){
Scanner in=new Scanner(System.in);//输入的前提语句
n=in.nextInt();//输入多少个数字
k=in.nextInt();//输入k
a=new int[n+1];//java的特性,充分利用空间
s=new int[n+1];
s[0]=0;//因为我们输入是从1开始的
for(int i=1;i<=n;i++) {
a[i]=in.nextInt();
s[i]=s[i-1]+a[i];//得到前i项和,即前缀和
}
long ans=0;
//枚举i,j
for(int i=1;i<=n;i++) {
for(int j=i;j<=n;j++) {
//ij之间的区间和=s[j]-s[i-1]
if((s[j]-s[i-1])%k==0) {
ans++;
}
}
}
System.out.println(ans);
}
}
🍊🍊思路二代码
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
public class Main
{
static int n,k;
static int[]a;
static int[]s;
static Map<Integer,Long> cnt=new HashMap<Integer,Long>();//同余的个数统计
public static void main(String[] args){
Scanner in=new Scanner(System.in);//输入的前提语句
n=in.nextInt();//输入多少个数字
k=in.nextInt();//输入k
a=new int[n+1];//java的特性,充分利用空间
s=new int[n+1];
s[0]=0;//因为我们输入是从1开始的
cnt.put(0,1l);//1l就是为long型的1
for(int i=1;i<=n;i++) {
a[i]=in.nextInt();
s[i]=(s[i-1]+a[i])%k;//得到前i项和对k的余数,即前缀和的余数
if(cnt.get(s[i])==null) {
cnt.put(s[i], 1l);
}
else {
cnt.put(s[i], cnt.get(s[i])+1);
}
}
long ans=0;
for(int i=0;i<k;i++) {//余数必然在0~k-1之间
Long cntI=cnt.get(i);
if(cntI==null) cntI=0l;
ans+=cntI*(cntI-1)/2;//例如所有前缀和中%k=3的有3个,那么他们任意选2可得一个k倍区间,c32
}
System.out.println(ans);
}
}
🍋其他真题
链接: 最全的2021蓝桥杯算法课《算法很美》的学习笔记总目录+真题详解.