[bzoj1044] [HAOI2008]木棍分割
阿新 • • 發佈:2019-02-15
++ 接下來 con 優化 const utc bzoj ems haoi2008
Description
有n根木棍, 第i根木棍的長度為Li,n根木棍依次連結了一起, 總共有n-1個連接處. 現在允許你最多砍斷m個連接處, 砍完後n根木棍被分成了很多段,要求滿足總長度最大的一段長度最小, 並且輸出有多少種砍的方法使得總長度最大的一段長度最小. 並將結果mod 10007。。。
Input
輸入文件第一行有2個數n,m.接下來n行每行一個正整數Li,表示第i根木棍的長度.n<=50000,0<=m<=min(n-1,1000),1<=Li<=1000.
Output
輸出有2個數, 第一個數是總長度最大的一段的長度最小值, 第二個數是有多少種砍的方法使得滿足條件.
Sample Input
3 2
1
1
10
Sample Output
10 2
Solution
第一問二分+貪心,第二問直接前綴和優化dp就好了,dp要滾動一維。
#include<bits/stdc++.h> using namespace std; void read(int &x) { x=0;int f=1;char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-f; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';x*=f; } void print(int x) { if(x<0) putchar('-'),x=-x; if(!x) return ;print(x/10),putchar(x%10+48); } void write(int x) {if(!x) putchar('0');else print(x);putchar('\n');} const int maxn = 2e5+10; const int mod = 10007; int n,m,a[maxn],q[maxn],f[2][maxn],ans,sum[maxn],r[maxn],w[maxn]; int check(int x) { int res=0,tmp=0; for(int i=1;i<=n;i++) { res+=a[i]; if(a[i]>x) return 0; if(res>x) res=a[i],tmp++; }return tmp<=m; } void solve1() { int l=0,R=sum[n],mid; while(l<=R) if(check(mid=((l+R)>>1))) R=mid-1,ans=mid;else l=mid+1; printf("%d ",ans); } void solve2() { for(int i=1;i<=n;i++) if(sum[i]<=ans) f[0][i]=1;else break; for(int i=1,lst=0;i<=n;i++) {while(sum[i]-sum[lst]>ans) lst++;r[i]=lst;} int res=f[0][n]; for(int t=1;t<=m;t++) { int i=t&1;memset(f[i],0,(n+4)*4); for(int j=1;j<=n;j++) w[j]=(w[j-1]+f[i^1][j])%mod; for(int j=1;j<=n;j++) f[i][j]=(w[j-1]-w[max(r[j]-1,0)])%mod; res=(res+f[i][n])%mod; }write((res+mod)%mod); } int main() { read(n),read(m); for(int i=1;i<=n;i++) read(a[i]),sum[i]=sum[i-1]+a[i]; solve1();solve2(); return 0; }
[bzoj1044] [HAOI2008]木棍分割