题解:
第一问二分答案
第二问用f[i][j]表示前i块分成j段的方案数
但是MLE
于是改变枚举顺序
先枚举j,然后i这一层用滚动数组优化
f[i][j]=sigma f[k][j-1](sum[i]-sum[k]<=ans)
决策是一段区间,而且左端点单调,搞个指针维护最左的决策点
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=100009;
const int mm=10007;
int n,m;
int s[maxn]={0};
int tot=0;
int l=0,r=0,mid=0,ans=0;
int f[maxn]={0};
int g[maxn]={0};
int Isok(){
int last=0,cnt=0;
for(int i=1;i<=n;++i){
if(s[i]-s[last]>mid){
++cnt;last=i-1;
}
}
++cnt;
if(cnt>m)return 0;
else return 1;
}
int main(){
scanf("%d%d",&n,&m);++m;
for(int i=1;i<=n;++i){
scanf("%d",&s[i]);
l=max(l,s[i]);
s[i]+=s[i-1];
}
r=1000000000;
while(l<=r){
mid=(l+r)>>1;
if(Isok()){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
printf("%d ",ans);
for(int i=1;i<=n;++i){
if(s[i]<=ans)g[i]=1;
else g[i]=0;
}
for(int j=2;j<=m;++j){
for(int i=1;i<=j-1;++i)f[j]=0;
int tm=g[j-1],last=j-1;
for(int i=j;i<=n;++i){
while((s[i]-s[last]>ans)){
tm=(tm-g[last]+mm)%mm;++last;
}
f[i]=tm;
tm=(tm+g[i])%mm;
}
tot=(tot+f[n])%mm;
// for(int i=1;i<=n;++i)cout<<f[i]<<' ';
// cout<<endl;
for(int i=1;i<=n;++i)g[i]=f[i];
}
printf("%d\n",tot);
return 0;
}