最大值最小化

最大值最小化

maxmin.pas/cpp

题目描述:

把一个包含n 个正整数的序列划分为m 个连续的子序列(每个正整数恰

好属于一个序列)。设第i 个序列的各数之和为S(i),你的任务是让所

有S(i)的最大值尽量小。例如序列1 2 3 2 5 4 划分成3 个序列的最优

方案为1 2 3|2 5 |4,其中S(1)、S(2)、S(3)分别为6、7、4,最大值

为7;如果划分成1 2|3 2|5 4,则最大值为9,不如刚才的好。

n<=10^6,所有数之和不超过10^9。

输入格式:

第一行输入n,m(1<=m<=n<=10^6)。

接下来一行输入n 个正整数,每个数不超过1000。

输出格式:

输出答案。

输入输出样例:

Maxmin.in maxmin.out

6 3

1 2 3 2 5 4

7

数据范围:

30%的数据满足:1<=m<=n<=500;

50%的数据满足:1<=m<=n<=5000;

100%的数据满足:1<=m<=n<=1000000。

 

****(考试时的思路)按最平均的方法分子序列,然后把最大的序列和隔壁的换值一直换到不能更小的为止且每次换完都重新排列。看起来很高大上的思想然后0分啦。

 1 #include<cstdio>
 2 #include<cmath>
 3 #include<algorithm>
 4 #include<cstring>
 5 using namespace std;
 6 long long int a[1000001],m,n,left=0,right = 0;
 7 bool check(long long int r)  //判断这个最大值是否合理 
 8 {
 9     long long int all=1,i,sum=0;    
10     for(i = 1;i <= n;i++)
11     {
12         sum += a[i];   //从前往后加,如果大于最大值了则段数加一 求出需要的最少段数 
13         if(sum > r)
14         {
15             all++;
16             if(all > m)    return false;    //如果需要的段数大于要求的段数就表示不满足要求 
17             sum=a[i]; //且新一段就从这个值开始
18         }
19     }
20     return true;  //满足要求 
21 }
22 long long int find(long long int l,long long int r)
23 {
24     long long int i=l,j=r,m;
25     while(i <= j)
26     {
27         m = (i + j) / 2; //二分取中间值,也就相当于新的最大值 
28         if(check(m)==true)  //如果最小值到这个中间值能成立一个划分方法那么下一次搜索最小值到这个中间值再小一点 
29             j = m - 1;
30         else     //如果不成立 
31             i = m + 1;  //下一次搜索后半段。 
32         find(i,j);  //完事儿再接着搜索新的区间 
33     }
34     return i;      //二分结束后输出答案 
35 }
36 int main()
37 {
38     long long int ans,i;
39     scanf("%lld %lld",&n,&m);
40     for(i = 1;i <= n;i++)
41     {
42         scanf("%lld",&a[i]);
43         if(left < a[i])
44             left = a[i];  //LEFT存放子序列的最小值也就是这些单个数组里面的最大值。 
45         right += a[i];   //RIGHT存放子序列最大值也就是所有数相加的和。 
46     }
47     ans = find(left,right); //搜索这个区间里面的值 
48     printf("%lld",ans);
49     return 0;
50 }

***这道题可以用二分动态规划,上面给代码的备注是二分的。备注应该够详细了吧。。

转载于:https://www.cnblogs.com/rax-/p/8821724.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值