工资

(money/money.in/money.out)
时限1000ms 内存256MB
聪哥在暑假参加了打零工的活动,这个活动分为n个工作日,每个工作日的工资为Vi。有m个结算工钱的时间,聪哥可以自由安排这些时间,也就是说什么时候拿钱,老板说的不算,聪哥才有发言权!(因为聪哥是土豪,他是老板的老板)
聪哥不喜欢身上一次性有太多的钱,于是他想安排一下拿钱的时间,使他一次性拿的钱中最大的最小。(最后一天一定要领钱)
输入
第一行 2个数 n,m
接下来n行,每行一个数,代表Vi.
输出
最小的最大钱数。
样例输入
7 5
100
400
300
100
500
101
400
样例输出
500
样例说明 
100 400//300 100//500//101//400////”表示老大要去拿钱。
数据范围
20%   1<=n<=2020%  1<=n<=50,Vi的和不超过1000
100%  1<=n<=100,000,m<=n,Vi<=10,000
题面

明显,二分答案,是的最大的区间段和最小

还有一个限制条件,最后一天必须结算

判断的时候加以分析就好了

分值:100/100

 1 #include<algorithm> 
 2 #include<iostream>
 3 #include<cstring>
 4 #include<string>
 5 #include<cstdio>
 6 #include<queue>
 7 #include<cmath>
 8 #define ll long long
 9 #define DB double
10 using namespace std;
11 inline int read()
12 {
13     int x=0,w=1;char ch=getchar();
14     while(!isdigit(ch)){if(ch=='-') w=-1;ch=getchar();}
15     while(isdigit(ch)) x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
16     return x*w;
17 }
18 const int N=1e5+100;
19 int n,m,a[N],M;
20 ll ans,L,R,mid,k;
21 bool v[N];
22 bool ok(ll x)
23 {
24     M=0;k=0;v[n]=0;
25     for(int i=1;i<=n;++i)
26     {
27         if(x<a[i]) return 0;
28         k+=a[i];
29         if(k>x) M++,k=a[i],v[i-1]=1;
30 //        cout<<k<<" "<<M<<" "<<i<<endl;
31         if(M>m) return 0;
32     }
33     if(k>x) return 0;
34 //    cout<<k<<" "<<v[n]<<endl;
35     if(!v[n]){v[n]=1;M++;}
36     if(M<=m) return 1;
37     return 0;
38 }
39 int main()
40 {
41     freopen("money.in","r",stdin);
42     freopen("money.out","w",stdout);
43     n=read();m=read();
44     for(int i=1;i<=n;++i) a[i]=read(),R+=a[i];
45 //    cout<<ok(38);
46     while(L<=R)
47     {
48         mid=(L+R)>>1;
49         if(ok(mid)) ans=mid,R=mid-1;
50         else L=mid+1;
51     }
52     printf("%lld",ans);
53     return 0;
54 }
View Code
posted @ 2018-05-13 17:18  月亮茶  阅读(154)  评论(0编辑  收藏  举报