题解:
第一问二分答案
第二问用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; }