[bzoj1044]木棍分割
第一个问题可以用贪心+二分解决
第二个问题用f[i][j]表示i次分割后分割到j且满足条件的方案数,$f[i][j]=\sum_{k<j且sum[j]-sum[k]<=ans}f[i-1][k]$
优化时间:前缀和优化,二分要先预处理出来(也可以用优先队列)
优化空间:发现f并没有什么用处,只需要记录前缀和数组,再对其滚动即可
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define mod 10007 4 int n,m,ans,a[50005],b[50005],sum[2][50005]; 5 bool pd(int k){ 6 int s=0,ans=0; 7 for(int i=1;i<=n;i++){ 8 s+=a[i]; 9 if (s>k){ 10 ans++; 11 s=a[i]; 12 } 13 } 14 return ans<=m; 15 } 16 int main(){ 17 scanf("%d%d",&n,&m); 18 for(int i=1;i<=n;i++)scanf("%d",&a[i]); 19 int l=0,r=1000*n; 20 for(int i=1;i<=n;i++)l=max(l,a[i]); 21 while (l<r){ 22 int mid=(l+r>>1); 23 if (pd(mid))r=mid; 24 else l=mid+1; 25 } 26 for(int i=2;i<=n;i++)a[i]+=a[i-1]; 27 for(int i=1;i<=n;i++)sum[0][i]=(sum[0][i-1]+(a[i]<=l))%mod; 28 for(int i=1;i<=n;i++)b[i]=lower_bound(a+1,a+n+1,a[i]-l)-a-1; 29 ans=(a[n]<=l); 30 for(int i=1;i<=m;i++){ 31 int p=(i&1); 32 for(int j=i+1;j<=n;j++){ 33 r=(sum[p^1][j-1]-sum[p^1][b[j]]+mod)%mod; 34 sum[p][j]=(sum[p][j-1]+r)%mod; 35 if (j==n)ans=(ans+r)%mod; 36 } 37 } 38 printf("%d %d",l,ans); 39 }