您的位置:首页 > 其它

【NOIP2015】推销员

2016-11-03 20:26 357 查看

推(chuan)销员

分析

这里主要阐述一下我的分析思路。

看起来挺直观的。

最初的想法,我们枚举每一个最远点mxp的位置,然后对之前的a进行排序。

那么以mxp为最远点,选x个的最大疲劳值为:

2∗s[mxp]+a[mxp]+(之前的前x−1大的a值的和)

这样的复杂度为O(n2logn),考试时就这样拿了个60pt。

但是,我们要尝试发现这道题的特性,来进行时间上的优化。

根据极大化思想,我们要尽可能排除不影响答案的(mxp,x)。

当x一定时,设i<j,i没有j优,这等价于:

2∗s[i]+a[i]+(i之前的前x−1大的a值的和)<2∗s[j]+a[j]+(j之前的前x−1大的a值的和)

记w[i]=2∗s[i]+a[i]

∴w[i]−w[j]<(j之前的前x−1大的a值的和)−(i之前的前x−1大的a值的和)

当x增大的时候,例如x变大到x+1,发现(j之前的前x大的a值的和)−(i之前的前x大的a值的和)的值一定是递增的,因为j之前的前x大的a值的和一定是j之前的前x−−1大的a值的和多一个数,i也一样,而i能选择到的j也能选择得到。

所以我们得到了决策单调性:对于x,i<j,i没有j优,那么随着x的增大,i仍然没有j优,所以对于x的询问的决策点会非严格单调递增。

接下来,很容易想到用单调队列什么的进行维护。

但怎么尝试都觉得不行……

这时候就一定要跳出来啦。

根据决策单调性这个重要的特点,考虑换一种思考的角度。

假如当前x−1这个询问我们决策点为cur,答案为res,现在要求x这个询问的决策点和答案。

我们有两种方法:

①在cur之前选择一个没有选择过的点i,Δ=a[i]

②在cur之后选择一个决策点,Δ=2∗s[i]+a[i]−2∗s[cur]

用两个堆实现即可。

有点意思。

代码

#include <cstdio>
#include <cctype>
#include <queue>
using namespace std;

#define rep(i,a,b) for (int i=(a);i<=(b);i++)

#define x first
#define y second
#define mp make_pair

typedef pair<int,int> PII;

const int N=131072;

int n;
int s
,a
;

int cur,vis
;
priority_queue<PII> qs,qb;
int res;

inline int rd(void)
{
int x=0,f=1; char c=getchar();
for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
for (;isdigit(c);c=getchar()) x=x*10+c-'0';
return x*f;
}

int main(void)
{
//  freopen("a.in","r",stdin);
//  freopen("a.out","w",stdout);

n=rd();
rep(i,1,n) s[i]=rd();
rep(i,1,n) a[i]=rd();

rep(i,1,n)
qb.push(mp(2*s[i]+a[i],i));

PII t1,t2; int e1,e2,cs;
rep(i,1,n)
{
while (!qs.empty())
{
t1=qs.top();
if (vis[t1.y])
qs.pop();
else break;
}
while (!qb.empty())
{
t2=qb.top();
if (t2.y<cur||vis[t2.y])
qb.pop();
else break;
}

e1=(!qs.empty());
e2=(!qb.empty());
if (!e1&&e2)
cs=2;
else if (e1&&!e2)
cs=1;
else if (e1&&e2)
{
t1=qs.top(),t2=qb.top();
if (t2.x-2*s[cur]>=t1.x)
cs=2;
else cs=1;
}

if (cs==1)
{
t1=qs.top(); qs.pop();
vis[t1.y]=1;
res+=t1.x;
}
else if (cs==2)
{
t2=qb.top(); qb.pop();
vis[t2.y]=1;
rep(j,cur+1,t2.y)
if (!vis[j])
qs.push(mp(a[j],j));
res+=(t2.x-2*s[cur]);
cur=t2.y;
}

printf("%d\n",res);
}

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: