传送门
解题思路
第一种:
对于选i家,很显然,a值前i-1家的一定会选,所以只需要考虑最后一家的选法。要么是选择a值第i大的(就不管s了),要么选择剩下的中s最大的。
我们把每一家的情况(s和a)存入几个结构体中,按照a的值从大到小排序,再用sum求出a的前缀和,用maxs[i]表示前i家中最大的s,用maxa[i]表示在i...n家中选一家的最大价值,即(s*2+a)的最大值。
然后对于要求的每一个i,ans[i]就是
- 选a值最大的前i家
- 选a值最大的前i-1家加上剩下的i...n家中贡献最大的那家
中的最大值,即
ans[i]=max(sum[i]+2*maxs[i],sum[i-1]+maxa[i]))。
第二种:
很显然,ans随着i的增大递增,所以用一个ans记录答案,每一次加上一个数。
对于每一次选择,可以分为两种情况,设距离最远的一家的地址为now:
- 选择地址<now的a值最大的那一家k,对答案的贡献为a[k]
- 选择地址>now的对答案贡献最大的那一家k,对答案的贡献为a[k]+2*(s[k]-now)
所以每次取max即可。
这里用两个大跟堆来实现比较方便。
q1存的是在now左面的点,q2存的是now右面的点。
如果更新右面的点,就q2弹出去一个,然后把q1中加入所有坐标在now和q2.top()的坐标之间的点,最后更新now的值。
如果更新的是左面的点,就q1弹出,q2不做处理。
这样,在每次取q2中的点时,就要先弹出所有坐标小于now的点。
AC代码
1 #include<iostream> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstdio> 5 using namespace std; 6 const int maxn=100005; 7 int n,maxs[maxn],maxa[maxn]; 8 struct node{ 9 int s,a; 10 bool operator <(const node &xx) { 11 return a>xx.a; 12 } 13 }x[maxn]; 14 int sum[maxn]; 15 int main() 16 { 17 cin>>n; 18 for(int i=1;i<=n;i++){ 19 scanf("%d",&x[i].s); 20 } 21 for(int i=1;i<=n;i++){ 22 scanf("%d",&x[i].a); 23 } 24 sort(x+1,x+n+1); 25 for(int i=1;i<=n;i++){ 26 sum[i]=sum[i-1]+x[i].a; 27 maxs[i]=max(maxs[i-1],x[i].s); 28 } 29 for(int i=n;i>=1;i--){ 30 maxa[i]=max(maxa[i+1],2*x[i].s+x[i].a); 31 } 32 for(int i=1;i<=n;i++){ 33 printf("%d\n",max(sum[i]+2*maxs[i],sum[i-1]+maxa[i])); 34 } 35 return 0; 36 }