先二分答案求出第一问
第二问dp
f[i][j]表示前j个分成i块的方案数
f[i][j]=sigmaf[i-1][k](sum[j]-sum[k]<=mx)
sum是单调的滚动数组加维护一个前缀和
复杂度(n*m)
#include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<queue> #include<vector> #include<set> #include<map> #include<algorithm> #include<iostream> #define E 10007 #define T 50005 #define lowbit(x) (x&(-x)) using namespace std; int sc() { int i=0;char c=getchar(); while(c>'9'||c<'0')c=getchar(); while(c>='0'&&c<='9')i=i*10+c-'0',c=getchar(); return i; } int f[2][T],a[T],sum[T]; int n,m,mx,ans=0,L,R,K; bool jud(int x) { int sum=0,l=0,nd=0; while(l<n) { sum+=a[++l]; if(sum>x) sum=a[l],nd++; if(sum>x) return 0; } return nd<=m; } int main() { n=sc(),m=sc(); for(int i=1;i<=n;i++)a[i]=sc(),R+=a[i]; while(L<=R) { int mid=L+R>>1; if(jud(mid))mx=mid,R=mid-1; else L=mid+1; } for(int i=1;i<=n;i++)a[i]+=a[i-1]; f[0][0]=1; for(int i=1;i<=m+1;i++) { int l=i&1,p=l^1,K=0; sum[0]=f[p][0]; for(int j=1;j<=n;j++) sum[j]=(sum[j-1]+f[p][j])%E; f[l][0]=0; for(int j=i;j<=n;j++) { while(a[j]-a[K]>mx)K++; f[l][j]=(sum[j-1]-(K?sum[K-1]:0))%E; } ans=(ans+f[l][n])%E; } cout <<mx<<" "<<(ans+E)%E; return 0; }