同步发表于洛谷博客
前言
又是一场废掉的CF啊……
题意
给定一个序列,把这个序列分成多段,使每段之和相等,求最大段长度的最小值。
思路
注意到, n n n 的数据范围是小于 2000 2000 2000, t t t 小于 100 100 100,那么考虑一种 O ( n 2 t ) \mathcal O(n^{2}t) O(n2t) 的暴力算法: 枚举第一段的长度, 将第一段的和作为基准,判断若以这种基准为每段之和是否可行。取每种可行方案下最大子段长度的最小值。
Code
#include <bits/stdc++.h>
using namespace std;
int t;
int n;
long long a[2001],b[2001];
int main() {
cin >> t;
while(t--) {
memset(b,0,sizeof(b));
memset(a,0,sizeof(a));//数组初始化
cin >> n;
for (int i=1; i<=n; i++) cin >> a[i],b[i]=a[i]+b[i-1];//b数组维护前缀和
int ans=0x3f3f3f3f;
for (int i=1; i<=n; i++) {
int maxn=i,cnt=0;//统计以前i个数之和为每个段的和的方案下,最大段的长度,maxn是这种方案下最大子段长度,cnt记录当前子段长度
long long sum=0;
for (int j=i+1; j<=n; j++) {//从第i+1个数开始统计,最大段的长度
sum+=a[j];
cnt++;
if (sum==b[i]) sum=0,maxn=max(maxn,cnt),cnt=0;
else if (sum>b[i]) {
sum=-1;
break;
}//若此方案不行,则跳出
}
if (sum<b[i]&&sum!=0) continue;//特判第i个数之后全部数之和仍小于前i个数之和情况
if (sum!=-1)
ans=min(maxn,ans);
}
cout << ans << endl;
}
return 0;
}