洛谷P2672 NOIP2015普及組第四題

題目描述

      阿明是一名推銷員,他奉命到螺絲街推銷他們公司的產品。螺絲街是一條死衚衕,出口與入口是同一個,街道的一側是圍牆,另一側是住戶。螺絲街一共有N家住戶,第i家住戶到入口的距離爲Si米。由於同一棟房子裏可以有多家住戶,所以可能有多家住戶與入口的距離相等。阿明會從入口進入,依次向螺絲街的X家住戶推銷產品,然後再原路走出去。

      阿明每走1米就會積累1點疲勞值,向第i家住戶推銷產品會積累Ai點疲勞值。阿明是工作狂,他想知道,對於不同的X,在不走多餘的路的前提下,他最多可以積累多少點疲勞值。

輸入格式:

第一行有一個正整數N,表示螺絲街住戶的數量。

接下來的一行有N個正整數,其中第i個整數Si表示第i家住戶到入口的距離。數據保證S1≤S2≤…≤Sn<10^8。

接下來的一行有N個正整數,其中第i個整數Ai表示向第i戶住戶推銷產品會積累的疲勞值。數據保證Ai<10^3。

輸出格式:

輸出N行,每行一個正整數,第i行整數表示當X=i時,阿明最多積累的疲勞值。

輸入輸出樣例

輸入樣例#1 

5
1 2 3 4 5
1 2 3 4 5

輸出樣例#1 

15
19
22
24
25

輸入樣例#2 

5
1 2 2 4 5
5 4 3 4 1

輸出樣例#2

12
17
21
24
27

解題思路:

      這道題目可以有兩種做法,一種是貪心,一種是線段樹。

      貪心如何去做呢?首先,要按照每戶的疲勞度去從大到小排序,然後,逐個去搜索,即可得到答案。

      線段樹的話~~~這種模板,應該就用不着解釋了吧~~~

代碼:(請不要直接拷貝哦)

//貪心
#include <cstdio>
#include <algorithm>
struct pl{
    int s,val;
}a[100005];
int maxx,j,k,ans;
using namespace std;
bool cmp(pl x,pl y)
{
    return x.val>y.val;//按照向每家推銷的疲勞度排序
}
int main()
{
    int n;
    //freopen("1.in","r",stdin);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&a[i].s);
    for (int i=1;i<=n;i++) scanf("%d",&a[i].val);
    sort(a+1,a+n+1,cmp);
    for (int i=1;i<=n;i++)
      if (2*a[i].s+a[i].val>maxx)//噹噹前這戶人家來回的疲勞度+推銷的疲勞度最大時,這就是我們需要找到的第一個答案
      {
      	maxx=2*a[i].s+a[i].val;//記錄下來
      	j=k=i;//記住這個點,下次搜尋時這個點不要再算了,否則會WA的
      }
    ans+=maxx;
    printf("%d\n",ans);
    for (int i=1;i<=n;i++)
    {
        if (i==k) continue;//搜尋過了,直接跳過
        if (a[j].s<a[i].s)
        {
            ans=ans-2*a[j].s+2*a[i].s+a[i].val;//重新計算答案
            j=i;
            printf("%d\n",ans);
        } else
        {
            ans+=a[i].val;
            printf("%d\n",ans);
        }
    }
    return 0;
}

===========================================================================

//線段樹
#include <cstdio>
#include <algorithm>
struct TREE{
    int l,r,mid,lazy,number,val;
}tree[400005];
int s[100005],a[100005];
int ans,now,last;
using namespace std;
inline void push_up(int x)
{
    if (tree[x*2].val>=tree[x*2+1].val)
    {
        tree[x].number=tree[x*2].number;
        tree[x].val=tree[x*2].val;
    } else
    {
        tree[x].number=tree[x*2+1].number;
        tree[x].val=tree[x*2+1].val;
    }
}
inline void push_down(int x)
{
    tree[x*2].val+=tree[x].lazy;
    tree[x*2+1].val+=tree[x].lazy;
    tree[x*2].lazy+=tree[x].lazy;
    tree[x*2+1].lazy+=tree[x].lazy;
    tree[x].lazy=0;
}
inline void build(int x,int l,int r)
{
    tree[x].l=l,tree[x].r=r,tree[x].mid=(l+r)/2;
    if (l==r)
    {
        tree[x].number=l;
        tree[x].val=s[l]*2+a[l];
        return;
    }
    build(x*2,l,tree[x].mid);
    build(x*2+1,tree[x].mid+1,r);
    push_up(x);
}
inline void change(int x)
{
    if (tree[x].r<=last) return;
    if (tree[x].l>now)
    {
        tree[x].val-=(s[now]-s[last])*2;
        tree[x].lazy-=(s[now]-s[last])*2;
        return;
    }
    if (tree[x].l==tree[x].r)
    {
        tree[x].val=a[tree[x].l];
        return;
    }
    if (tree[x].lazy) push_down(x);
    change(x*2);
    change(x*2+1);
    push_up(x);
}
inline void xg(int x)
{
    if (tree[x].l==tree[x].r)
    {
        tree[x].val=-600000000;
        return;
    }
    if (now<=tree[x].mid) xg(x*2);
      else xg(x*2+1);
    push_up(x);
}
int main()
{
    int n;
    //freopen("1.in","r",stdin);
    scanf("%d",&n);
    for (int i=1;i<=n;i++) scanf("%d",&s[i]);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    build(1,1,n);//建樹
    for (int i=1;i<=n;i++)
    {
        ans+=tree[1].val;//算答案,第一個即爲我們想要的值
        now=tree[1].number;
        printf("%d\n",ans);
        if (now>last)
        {
            change(1);//改變樹
            last=now;//更新last
        }
        xg(1);//將now刪除掉
    }
    return 0;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章