话不多说先贴原题:
给定一个由n个整数组成的数组a1,a2,…,和整数k。您必须将数组拆分成k个非空的子段。然后,您将计算每个子段上的最小整数,并获取超过k个最小值的最大整数。你可以得到最大可能的整数是多少?
输入
第一行包含两个整数n和k(1≤k≤n≤10^5) - 数组a的大小和必须将数组拆分的子段数。
第二行包含n个整数a1,a2,…,an( - 10^9≤ai≤10^9)。
首先,分析题目,解的情况只有三种:
- k=1,这种情况最简单,由于只分一块,所以不难发现答案就是该数组的最小值。
- k>=3,此时原数组至少会被分成三块,所以只要将数组最大值单独分成一块,就可以使最终结果最大,所以此时答案是该数组的最大值。
- k=2,此时原数组被分为两块(下面称之为左(右)块),首先不妨设该数组的最小值处于数组中间某位置,此时从数组的一端(设为左端)开始尝试分块。若将端点值单独分为一块,则最大结果一定是该端点值,如图示:
a1 | a2,…,min,…,an ( | 代表分割位置)。
现在开始将分割位置逐位右移,对于伴随着分割位置的每一次右移,从右块进入左块的元素 X,若 (X>=a1) 则对于最终结果没有影响,若 (X<=a1)则该次右移“不合算”,因为此时的结果成了 X,而 X<=a1,使最终结果变小。所以当 K=2时,将端点元素单独分一组即为最优分割法,同时将上述步骤从右端开始,也可以得到相同的结论,所以,K=2时,答案就是数组的两个端点值中较大的。
还有一个问题,由于k,n的取值太大,数组开不下,只能采用边读入边处理的方法。
最后码程序:
#include<stdio.h>
int main(void)
{
long long int n,k,i,ans,min,max,x;
scanf("%lld%lld\n",&n,&k);
max=-1000000009;
min=1000000009;
if (k==1)
{
for(i=1;i<=n;i++)
{
scanf("%lld",&x);
if (x<min) min=x;
}
ans=min;
}
else if (k>=3)
{
for(i=1;i<=n;i++)
{
scanf("%lld",&x);
if (x>max) max=x;
}
ans=max;
}
else
{
scanf("%lld",&max);
for (i=2;i<=n;i++) scanf("%lld",&x);
if (max>x) ans=max;
else ans=x;
}
printf("%lld",ans);
return 0;
}