题目描述
阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有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; }