#include <stdio.h>
int main()
{
puts("转载请注明出处[vmurder]谢谢");
puts("网址:blog.csdn.net/vmurder/article/details/44622633");
}
首先我们从大到小排个序,然后感性来讲,肯定是从大到小能取多少就取多少的。然后我们取一个点时,还不能取多了,不符题意或者影响到其它已经取了的点对吧。
所以我们求个前驱pre,后缀suc,就是最近的前面的取了的点,和后面的。
这个可以用线段树求,也可以set神马的快速水过啦啦啦。
然后此点既然是之前取的,肯定是能取多少尽量取多少啦,拿后缀举例,也就是你取当前点,然后等到后缀那个点,肯定需要恢复完全才可以,不能当前点取太多影响到后缀那个点取了的数量对吧。
我们研究此点、前驱、后继之间的关系,以此来确定此点能取多少。
首先到每个点时次数不能大于limit,这是第一个限制
首先前驱那里一定是取完了,所以到这个点时至多回复了两点距离天数*recover/day。
然后后继那里同理,也是距离*recover
然后前驱和后继之间肯定是不互相影响或者说影响过了的。
那么其中最多插入前驱后继距离*recover-limit的次数。
long long temp=lim;
if(pre>=1)temp=min(temp,(long long)(src[i].id-pre)*rec);
if(suc<=n)temp=min(temp,(long long)(suc-src[i].id)*rec);
if(pre>=1&&suc<=n)temp=min(temp,(long long)(suc-pre)*rec-lim);
if(temp>0)
{
ans+=(long long)src[i].x*temp;
add(src[i].id);
}
然后如果取的次数负了的话肯定是不取了对吧。
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 501000
#define inf 0x3f3f3f3f
#define ls (note<<1)
#define rs (note<<1|1)
using namespace std;
int n,lim,rec,a[N];
long long ans;
struct Segment_Tree
{
int x,l,r;
}s[N<<2];
int crs[N];
void build(int note,int l,int r)
{
s[note].x=0;
s[note].l=l,s[note].r=r;
if(l==r)
{
crs[l]=note;
return ;
}
int mid=l+r>>1;
build(ls,l,mid),build(rs,mid+1,r);
}
inline void add(int x)
{
x=crs[x];
while(x)s[x].x++,x>>=1;
}
inline int pred(int note,int x) // [1,x]这段中最后一个有值的。
{
if(!s[note].x)return 0;
if(s[note].l==s[note].r)return s[note].l;
int mid=s[note].l+s[note].r>>1;
if(x>mid)
{
int ret=pred(rs,x);
if(ret)return ret;
else return pred(ls,s[ls].r);
}
else return pred(ls,x);
}
inline int succ(int note,int x) // [x,n]这段中最后一个有值的。
{
if(!s[note].x)return n+1;
if(s[note].l==s[note].r)return s[note].l;
int mid=s[note].l+s[note].r>>1;
if(x<=mid)
{
int ret=succ(ls,x);
if(ret<=n)return ret;
else return succ(rs,s[rs].l);
}
else return succ(rs,x);
}
struct ELI
{
int x,id;
bool operator < (const ELI &A)const
{return x<A.x;}
}src[N];
void work3()
{
ans=0;
int i,j,k;
for(i=1;i<=n;i++)
{
src[i].x=a[i];
src[i].id=i;
}
sort(src+1,src+n+1);
build(1,1,n);
for(i=n;i;i--)
{
int pre=pred(1,src[i].id);
int suc=succ(1,src[i].id);
long long temp=lim;
if(pre>=1)temp=min(temp,(long long)(src[i].id-pre)*rec);
if(suc<=n)temp=min(temp,(long long)(suc-src[i].id)*rec);
if(pre>=1&&suc<=n)temp=min(temp,(long long)(suc-pre)*rec-lim);
if(temp>0)
{
ans+=(long long)src[i].x*temp;
add(src[i].id);
}
}
cout<<ans<<endl;
return ;
}
int main()
{
freopen("test.in","r",stdin);
// freopen("arbeit.out","w",stdout);
int i,j,k,g;
for(scanf("%d",&g);g--;)
{
scanf("%d%d%d",&lim,&rec,&n);
for(i=1;i<=n;i++)scanf("%d",&a[i]);
work3();
}
return 0;
}
原文:http://blog.csdn.net/vmurder/article/details/44622633