题意:给定一个长度为 n 的数组 s 和一个数 k,可以把 s 按顺序分成 m 组(m未知),但每一组的元素个数都必须相同,即每一组的元素个数为 n / m (末尾多余的元素舍去),分别累加 m 个组的最大值的和 sum,要求 sum>k,求出最小的 m 使得这个条件满足。
分析:RMQ+暴力优化,首先对于分组数m,最大肯定是 n,那最小呢,我们先用RMQ求出整个数组的最大元素 tmp,那么 t=(k+1)/tmp 即是分组的最小数,为什么?因为 k+1 至少是由 t 个 tmp 组成的,而 tmp 又是整个数组的最大值,所以至少得分 t 组,
即 (t<=m<=n); 然后对于当前分组 m,求出每个组的长度cnt=n/m,跳着跳着用RMQ累加最大值就行了。
代码:
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<functional>
using namespace std;
const int N = 200000+10;
int d[N][25],v[N];
int n,k;
void init()
{
for(int i=1;i<=n;i++) d[i][0]=v[i];
for(int i=1;(1<<i)<=n;i++)
for(int j=1;j+(1<<i)-1<=n;j++)
d[j][i]=max(d[j][i-1],d[j+(1<<(i-1))][i-1]);
}
int query(int l,int r)
{
int k=0;
while((1<<k)<=(r-l+1)) k++;
k--;
int ans=max(d[l][k],d[r-(1<<k)+1][k]);
return ans;
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
if(n<0&&k<0) break;
for(int i=1;i<=n;i++) scanf("%d",&v[i]);
init();
int limit=query(1,n),m;
for(m=max(1,(k+1)/limit);m<=n;m++)
{
int cnt=n/m;
int ans=0;
for(int j=1,p=0;p<m;p++,j+=cnt)
{
ans+=query(j,j+cnt-1);
if(ans>k) break;
}
if(ans>k) break;
}
if(m<=n) printf("%d\n",m);
else puts("-1");
}
}