http://bestcoder.hdu.edu.cn/contests/contest_showproblem.php?cid=892&pid=1003
考虑求最大值的构造方法,先把a数组从小到大排序
我们思考对于第一段长度为l的,要让更大的答案覆盖更多的区间,就肯定后k个从大到小倒序放,也就是在l-k+1的位置开始放a[n],a[n-1]....a[n-k+1]放到a[l],那么第一个区间的答案就为a[n-k+1],然后这个a[n-k+1]可以一直拓展到右坐标为l+l-k的位置,然后从右坐标l+l-k+1开始,a[n]就没了,需要新增一个a数组中剩余最大的,且他就是这个区间为右端点的答案。
那么我们可以想到对于全局应该就是以 l 分段,每一段的后k个倒序从大到小,这样就能得到最大值
求最大值的答案可以把放了的地方都放上值,没放的地方都放上0,也就是这些不用管的位置小于放了的所有数字,然后滑动窗口,[l,r]->[l+1,r+1]时,只有b[l]放了,b[r+1]也放了,答案才会变成b[r+1],否则不变,这是由我们的构造方法决定的性质
求最小值就是对偶问题了,直接k=l-k+1,数组从大到小排,其他一样
#include<bits/stdc++.h>
#define pb push_back
using namespace std;
typedef long long ll;
const int maxl=3e5+10;
ll n,len,k,ansmi,ansmx,cas;
ll a[maxl],b[maxl];
char s[maxl];
bool in[maxl];
inline void prework()
{
scanf("%lld%lld%lld",&n,&len,&k);
for(int i=1;i<=n;i++)
scanf("%lld",&a[i]);
sort(a+1,a+1+n);
}
inline bool cmp(const int &a,const int &b)
{
return a>b;
}
inline void mainwork()
{
ansmx=0;
int now=n,l;
for(int i=1;i<=n;i++)
b[i]=0;
for(int i=1;i*len-k+1<=n;i++)
for(int j=i*len-k+1;j<=i*len && j<=n;j++)
b[j]=a[now--];
ll x=b[len];
for(int r=len;r<=n;r++)
{
l=r-len+1;
ansmx+=x;
if(r==n)
break;
if(b[l]>0 && b[r+1]>0)
x=b[r+1];
}
ansmi=0;k=len-k+1;
now=n;
for(int i=1;i<=n;i++)
b[i]=0;
sort(a+1,a+1+n,cmp);
for(int i=1;i*len-k+1<=n;i++)
for(int j=i*len-k+1;j<=i*len && j<=n;j++)
b[j]=a[now--];
x=b[len];
for(int r=len;r<=n;r++)
{
l=r-len+1;
ansmi+=x;
if(r==n)
break;
if(b[l]>0 && b[r+1]>0)
x=b[r+1];
}
}
inline void print()
{
printf("%lld %lld\n",ansmx,ansmi);
}
int main()
{
int t=1;
scanf("%d",&t);
for(cas=1;cas<=t;cas++)
{
prework();
mainwork();
print();
}
return 0;
}
本文详细解析了一种求最大值的构造算法,通过将数组排序并逆序放置元素,实现区间最大值的优化。同时,介绍了如何转换算法以求解最小值问题。

被折叠的 条评论
为什么被折叠?



