[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 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11756699.html