传送门 to luogu
问题描述
阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口
与入口是同一个,街道的一侧是围墙,另一侧是住房。螺丝街一共有 N N N 家住房,第 i i i 家住户
到入口的距离为 S i S_i Si 米。由于同一栋房子里可以有多家住户,所以可能有多家住房与入口的
距离相等。阿明会从入口进入,依次向螺丝街的 X X X 家住房推销产品,然后再原路走出去。
阿明每走 1 1 1 米就会积累 1 1 1 点疲劳值,向第 i i i 家住房推销产品会积累 A i A_i Ai 点疲劳值。阿明
是工作狂,他想知道,对于不同的 X X X ,在不走多余路的前提下,他最多可以积累多少点疲劳
值。
输入格式
第一行有一个正整数 N N N ,表示螺丝街住房的数量。
接下来的一行有 N N N 个正整数,其中第 i i i 个整数 S i S_i Si 表示第 i i i 家住户到入口的距离。数据
保证 S 1 ≤ S 2 ≤ … ≤ S n ≤ 1 0 8 S_1\le S_2≤…≤S_n≤10^8 S1≤S2≤…≤Sn≤108 。
接下来的一行有 N N N 个整数,其中第 i i i 个整数 A i A_i Ai 表示向第 i i i 户住户推销产品会积累的疲
劳值。数据保证 A i < 1 0 3 Ai<10^3 Ai<103 。
输出格式
输出 N N N 行,每行一个正整数,第 i i i 行整数表示当 X = i X=i X=i 时,阿明最多积累的疲劳值。
数据范围与提示
对于 20 % 20\% 20%的数据, 1 ≤ N ≤ 20 1≤N≤20 1≤N≤20 ;
对于 40 % 40\% 40%的数据, 1 ≤ N ≤ 100 1≤N≤100 1≤N≤100 ;
对于 60 % 60\% 60%的数据, 1 ≤ N ≤ 1000 1≤N≤1000 1≤N≤1000 ;
对于 100 % 100\% 100%的数据, 1 ≤ N ≤ 100000 1≤N≤100000 1≤N≤100000 。
说明:为了行文方便,以下称 “一户人家” 为 “点” ,将要推销的点的集合为 X X X 。
因为不走回头路,所以行走的疲劳值只有 2 max x ∈ X S x 2\max_{x\in X} S_x 2maxx∈XSx ,而推销疲劳值为 ∑ x ∈ X A x \sum_{x\in X}A_x ∑x∈XAx ,所以有:
a n s = 2 max x ∈ X S x + ∑ x ∈ X A x ans=2\max_{x\in X}S_x+\sum_{x\in X}A_x ans=2x∈XmaxSx+x∈X∑Ax
注意到 max x ∈ X S x \max_{x\in X}S_x maxx∈XSx 的变化是非常难的,所以,我们不妨假设一组解。
在这组解中,我们将 S S S 最大的点固定,剩下的点就可以任选,目的是让 ∑ A \sum A ∑A 最大。
很显然,剩下的点应当尽量去选择 A A A 比较大的,因为 S S S 已经不归它们管了。
所以,我们最多只需要一个点去得到较大的 S S S ,于是就至少会选前 i − 1 i-1 i−1 大的 A A A 。
固定了 i − 1 i-1 i−1 个极大的 A A A 之后,剩下的一个就应该综合考虑 S + A S+A S+A 了。这可以用 O ( n ) \mathcal O(n) O(n) 的预处理得到。
当然,也有可能不考虑 S + A S+A S+A ,直接全部选最大的 A A A , S S S 就听天由命了。还是可以预处理。
上面这种情况的本质是, S + A S+A S+A 中的 S S S 却没有已经固定的大 A A A 厉害。毕竟 S + A S+A S+A 的考虑是比较狭隘的——它只考虑不属于前 i i i 大的 A A A 的点。
#include
#include
#include
using namespace std;
struct Home{
int s,a;
bool operator<(const Home &x)const{
return a>x.a;
}
};
const int MAXN=100000;
int suma[MAXN+5],s_and_a[MAXN+5],maxs[MAXN+5];
Home home[MAXN+5];
int main()
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;++i)
scanf("%d",&home[i].s);
for(int i=1;i<=n;++i)
scanf("%d",&home[i].a);
sort(home+1,home+1+n);
for(int i=1;i<=n;++i)
{
maxs[i]=max(maxs[i-1],home[i].s);
suma[i]=suma[i-1]+home[i].a;
}
for(int i=n;i>=1;--i)
s_and_a[i]=max(s_and_a[i+1],home[i].s*2+home[i].a);
for(int i=1;i<=n;++i)
printf("%d\n",max(maxs[i]*2+suma[i],s_and_a[i]+suma[i-1]));
return 0;
}
我的所有博客中(我还是写了不少的),阅读比较多的竟然是这几篇:
我无话可说。您开心就好。