注意可以且m次,即分成m+1段。所以先让m加上1。
先做一个简单的二分答案算出最小的最大值。然后可以得到一个O(mn^2)的dp。
发现dp可以通过前缀和把时间复杂度优化为O(nm),通过滚掉记录m的那一维,把空间复杂度优化为O(n)。
#include <bits/stdc++.h>
#define left leftt
using namespace std;
const int N=5e4+5,MOD=10007;
int n,m,l,r,mid,ans,ans2,now;
int a[N],aa[N],left[N],f[N],sum[N];
inline bool jay(int mid)
{
int sum=1,now=0;
for (register int i=1; i<=n; ++i)
{
if (now+a[i]<=mid) now+=a[i];
else sum++,now=a[i];
if (sum>m) return false;
}
return true;
}
int main(){
scanf("%d%d",&n,&m); m++;
for (register int i=1; i<=n; ++i) scanf("%d",&a[i]),l=max(l,a[i]),r+=a[i];
for (register int i=1; i<=n; ++i) aa[i]=a[i];
while (l<=r)
{
mid=l+r>>1;
if (jay(mid)) ans=mid,r=mid-1;
else l=mid+1;
}
now=1;
for (register int i=1; i<=n; ++i)
{
a[i]+=a[i-1];
while (a[i]-a[now]>ans) now++;
left[i]=now;
}
now=0;
for (register int i=1; i<=n; ++i)
{
now+=aa[i];
if (now<=ans) f[i]=1;
}
sum[0]=0;
for (register int i=1; i<=n; ++i) sum[i]=(sum[i-1]+f[i])%MOD;
ans2=f[n];
for (register int j=2; j<=m; ++j)
{
for (register int i=1; i<=n; ++i) f[i]=((sum[i-1]-sum[left[i]-1])%MOD+MOD)%MOD;
sum[0]=0;
for (register int i=1; i<=n; ++i) sum[i]=(sum[i-1]+f[i])%MOD;
ans2=(ans2+f[n])%MOD;
}
printf("%d %d\n",ans,ans2);
return 0;
}