数组A[]={1,2,3,……}
给定一个长度为N的数组A=[A1, A2, … AN],请你将A拆分成3段连续的子数组:
A1, A2, … Ap | Ap+1, Ap+2, … Aq | Aq+1, Aq+2, … AN
令
S1 = A1 + A2 + … Ap
S2 = Ap+1 + Ap+2 + … Aq
S3 = Aq+1 + Aq+2 + … AN
问有多少种划分方案可以使得S1, S2, S3两两相差不超过1.
N <= 100000, -1000000 <= Ai <= 1000000
S[i]=s[i-1]+A[i]//s[i]表示A[0]+……+A[i]
1.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)
例子:
A = [1, 2, 3, 4, 5], K = 2
答案是6:[1, 2, 3], [1, 2, 3, 4], [2], [2, 3, 4, 5], [3, 4, 5], [4]
利用前缀和:A[i]+……+A[j]=s[j]-s[i-1]
思路:
枚举起点Ai和终点Aj,计算部分和SUM = s[j] – s[i-1]
如果SUM是K倍数,ans++
for i = 1 … N:
for j = i … N:
sum = s[j] – s[i-1]
if sum % K == 0:
ans++
此思路运行超时
package K倍区间;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
int n,k;
Scanner in=new Scanner(System.in);
n=in.nextInt();
k=in.nextInt();
int a[]=new int[n+1];
int sum[]=new int[n+1];
for(int i=1;i<=n;i++){
a[i]=in.nextInt();
sum[i]=sum[i-1]+a[i];
}
int ants=0;
for(int i=1;i<=n;i++){
for(int j=i;j<=n;j++){
if((sum[j]-sum[i-1])%k==0) ants++;
}
}
System.out.println(ants);
}
}
2.数组拆分
给定一个长度为N的数组A=[A1, A2, … AN],请你将A拆分成3段连续的子数组:
A1, A2, … Ap | Ap+1, Ap+2, … Aq | Aq+1, Aq+2, … AN
令
S1 = A1 + A2 + … Ap
S2 = Ap+1 + Ap+2 + … Aq
S3 = Aq+1 + Aq+2 + … AN
问有多少种划分方案可以使得S1, S2, S3两两相差不超过1.
N <= 100000, -1000000 <= Ai <= 1000000
简单思路:枚举边界p,q的位置,利用前缀和计算s1,s2,s3
package 数组拆分;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
// TODO Auto-generated method stub
int n;
Scanner in=new Scanner(System.in);
n=in.nextInt();
int a[]=new int[n+1];
int sum[]=new int[n+1];
for(int i=1;i<=n;i++){
a[i]=in.nextInt();
sum[i]=sum[i-1]+a[i];
}
int s1,s2,s3,ants=0;
for(int p=1;p<=n-2;p++){
for(int q=p+1;q<=n-1;q++){
s1=sum[p]-sum[0];
s2=sum[q]-sum[p];
s3=sum[n]-sum[q];
if(Math.abs(s1-s2)<=1&&Math.abs(s2-s3)<=1&&Math.abs(s3-s2)<=1){
ants++;
}
}
}
System.out.println(ants);
}
}