【題目連接】php
http://www.lydsy.com/JudgeOnline/problem.php?id=1044ios
【題意】git
n根木棍拼到一塊兒,最多能夠切m刀,問切成後最大段的最小值及其方案數。數組
【思路】優化
對於第一問能夠二分後貪心判斷。spa
假設第一問獲得的答案爲L,設f[i][j]前i個木棍切j下且保持段長不超過L的方案數,則有轉移式:指針
f[i][j]=sigma { f[k][j-1] },k<i,suma(k+1,i)<=Lcode
優化:blog
空間方面能夠用個滾動數組。get
時間方面因爲前綴和sum是遞增的,因此咱們拿個指針qf維護一個滑動窗口,使得窗口知足suma<=L,tot順便記一下和就出來了。
【代碼】
1 #include<set> 2 #include<cmath> 3 #include<queue> 4 #include<vector> 5 #include<cstdio> 6 #include<cstring> 7 #include<iostream> 8 #include<algorithm> 9 #define trav(u,i) for(int i=front[u];i;i=e[i].nxt) 10 #define FOR(a,b,c) for(int a=(b);a<=(c);a++) 11 #define rep(a,b,c) for(int a=(b);a>=(c);a--) 12 using namespace std; 13 14 typedef long long ll; 15 const int N = 1e5+10; 16 const int mod = 1e4+7; 17 18 ll read() { 19 char c=getchar(); 20 ll f=1,x=0; 21 while(!isdigit(c)) { 22 if(c=='-') f=-1; c=getchar(); 23 } 24 while(isdigit(c)) 25 x=x*10+c-'0',c=getchar(); 26 return x*f; 27 } 28 29 int n,m,ans,a[N],sum[N],f[2][N],cur,q[N],qf,qr; 30 31 bool can(int M) 32 { 33 int cnt=0,tot=0; 34 FOR(i,1,n) { 35 if(tot+a[i]>M) { 36 if((++cnt)>m) return 0; 37 tot=0; 38 } 39 tot+=a[i]; 40 } 41 return 1; 42 } 43 44 int main() 45 { 46 // freopen("in.in","r",stdin); 47 // freopen("out.out","w",stdout); 48 n=read(),m=read(); 49 int L=0,R=0; 50 FOR(i,1,n) 51 { 52 a[i]=read(), 53 sum[i]=sum[i-1]+a[i]; 54 L=max(L,a[i]); 55 } 56 R=sum[n]; 57 while(L<R) 58 { 59 int M=L+R>>1; 60 if(can(M)) R=M; else L=M+1; 61 } 62 printf("%d ",L); 63 64 FOR(j,0,m) 65 { 66 cur^=1; 67 int tot=0,qf=1; 68 FOR(i,1,n) 69 { 70 if(!j) f[cur][i]=sum[i]<=L; 71 else { 72 while(qf<i && sum[i]-sum[qf]>L) 73 tot=(tot-f[cur^1][qf++]+mod)%mod; 74 f[cur][i]=tot; 75 } 76 tot=(tot+f[cur^1][i])%mod; 77 } 78 ans=(ans+f[cur][n])%mod; 79 } 80 printf("%d\n",ans); 81 return 0; 82 }