原题
给定一个长度为 n
的数组 a1,a2,…,an
现在,要将该数组从中间截断,得到三个非空子数组。
要求,三个子数组内各元素之和都相等。
请问,共有多少种不同的截断方法?
输入格式
第一行包含整数 n
第二行包含 n
个整数 a1,a2,…,an
输出格式
输出一个整数,表示截断方法数量。
数据范围
前六个测试点满足 1≤n≤10
所有测试点满足 1≤n≤105
,−10000≤ai≤10000
输入样例1:
4
1 2 3 3
输出样例1:
1
输入样例2:
5
1 2 3 4 5
输出样例2:
0
输入样例3:
2
0 0
输出样例3:
0
👨🏫 关键思路:
将一个数组分为3个 和相等的 非空子数组,即每个数组的值为 1/3 * 数组所有元素和
import java.util.*;
import java.io.*;
class Main{
static int N = 100010;
static int[] s = new int [N];//前缀和数组
//使用 StreamTokenizer 需要抛出IO异常
public static void main(String args[])throws IOException{
// Scanner sc = new Scanner(System.in);
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
// int n = sc.nextInt();
in.nextToken();
int n = (int)in.nval;
for(int i = 1; i <= n; i++)
{
// s[i] = sc.nextInt();
// s[i] = s[i-1]+s[i];
in.nextToken();
s[i] = s[i-1] +(int)in.nval;
}
long res = 0;
int ave = s[n]/3;//平均数,即子数组的所有元素和
if(s[n] % 3 == 0)
{
int cnt = 0;
for(int i = 1;i < n-1; i++)//枚举到 n-2 ,后边留两个数切两刀
{
if(s[i] == ave)
cnt++;//记录什么地方可以切第一刀,cnt种可能
if(s[n]-s[i+1] == ave)
res+=cnt;//第二刀可以切的位置每多一种,总方案数就多 cnt 种可能
}
}
System.out.println(res);
}
}
👨🏫 使用 StreamTokenizer 显著改善输入耗时的问题