【codevs 5126】[NOIP2015 普及組T4]推銷員(貪心)
5126 推銷員 NOIP2015
時間限制: 1 s 空間限制: 128000 KB 題目等級 : 黃金 Gold
題目描述 Description
阿明是一名推銷員,他奉命到螺絲街推銷他們公司的產品。螺絲街是一條死衚衕,出口與入口是同一個,街道的一側是圍牆,另一側是住戶。螺絲街一共有N家住戶,第i家住戶到入口的距離為Si米。由於同一棟房子裡可以有多家住戶,所以可能有多家住戶與入口的距離相等。阿明會從入口進入,依次向螺絲街的X家住戶推銷產品,然後再原路走出去。阿明每走1米就會積累1點疲勞值,向第i家住戶推銷產品會積累Ai點疲勞值。阿明是工作狂,他想知道,對於不同的X,在不走多餘的路的前提下,他最多可以積累多少點疲勞值。
輸入描述 Input Description
第一行有一個正整數N,表示螺絲街住戶的數量。
接下來的一行有N個正整數,其中第i個整數Si表示第i家住戶到入口的距離。資料保證S1≤S2≤…≤Sn<10^8。
接下來的一行有N個正整數,其中第i個整數Ai表示向第i戶住戶推銷產品會積累的疲勞值。資料保證Ai<10^3。
輸出描述 Output Description
輸出N行,每行一個正整數,第i行整數表示當X=i時,阿明最多積累的疲勞值。
樣例輸入 Sample Input
【樣例1】
5
1 2 3 4 5
1 2 3 4 5
【樣例2】
5
1 2 2 4 5
5 4 3 4 1
樣例輸出 Sample Output
【樣例1】
15
19
22
24
25
【樣例2】
12
17
21
24
27
資料範圍及提示 Data Size & Hint
1≤N≤100000
【題解】【貪心】
【剛開始寫了個dp,O(n³),寫完看資料範圍就傻了。。。】
[40分碼]
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; int f[5010][5010],g[5010][5010]; int n,a[100010],len[100010]; int main() { int i,j; scanf("%d",&n); for(i=1;i<=n;++i)scanf("%d",&len[i]); for(i=1;i<=n;++i)scanf("%d",&a[i]); f[1][1]=len[1]*2+a[1]; g[1][1]=1; for(i=2;i<=n;++i) for(j=1;j<=i;++j) { f[i][j]=f[i-1][j]; g[i][j]=g[i-1][j]; for(int k=j-1;k<i;++k) { int sum=f[k][j-1]+(len[i]-len[g[k][j-1]])*2+a[i]; if(sum>f[i][j]) f[i][j]=sum,g[i][j]=i; } int sum=f[i-1][j-1]+(len[i]-len[g[i-1][j-1]])*2+a[i]; if(sum>f[i][j]) f[i][j]=sum,g[i][j]=i; } for(i=1;i<=n;++i)printf("%d\n",f[n][i]); return 0; }
【看上去十分科學,然而。。。】
【於是想把dp的實現過程改成線段樹,因為這明顯是區間取最優值的問題。但由於我從沒寫過,果斷棄了】
【開始亂搞貪心:最後想到應該是儘量取推銷時疲勞值大的,然後按路程為第一關鍵字排序,從小到大排,疲勞值為第二關鍵字排序,因為最優值一定是在前一次的最優值基礎上出現的(這並不是說下一次再找當前情況下的最大權值),即所以找的時候可以繼承上一次的查詢位置。但是,按照排序後的順序順次取,不一定是最優的,每次要向後列舉看有沒有更優的,下一次時,就接著上一次最優值的位置繼續查詢。優先佇列維護】
[在vijos上莫名WA掉。。。]
#include<queue>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node{
int val,road;
bool operator<(const node &a)const
{
return a.val>val;
}
}a[100010];
priority_queue<node>que;
int n,num[100010],nm[100010],tot,ans;
int tmp(node a,node b)
{
return (a.road<b.road||a.road==b.road&&a.val>b.val);
}
int main()
{
int i,j;
scanf("%d",&n);
for(i=1;i<=n;++i)scanf("%d",&a[i].road);
for(i=1;i<=n;++i)scanf("%d",&a[i].val);
sort(a+1,a+n+1,tmp);
for(i=1;i<=n;++i)
if(a[i-1].road==a[i].road) nm[tot]=i;
else num[++tot]=i,nm[tot]=i;
int last=0;
node x; x.road=x.val=0;que.push(x);
for(i=1;i<=n;++i)
{
node x=que.top();
int maxn=x.val,t=last;
for(int j=last+1;j<=tot;++j)
{
int u=num[j];
int sum=a[u].val+(a[u].road-a[last].road)*2;
if(sum>maxn) sum=maxn,t=j;
}
int u=num[t];
a[u].val+=(a[u].road-a[last].road)*2;
for(int j=nm[last]+1;j<=nm[t];++j) que.push(a[j]);
x=que.top(); que.pop();
ans+=x.val; last=t;
printf("%d\n",ans);
}
return 0;
}
#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
using namespace std;
#define N 100005
int n,Max,maxp,point;
int s[N],a[N],pt[N],ans[N];
bool vis[N];
struct hp
{
int val,loc;
bool operator < (const hp &a) const
{
return a.val>val;
}
};
priority_queue <hp> q;
priority_queue <hp> p;
int main()
{
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]);
for (int i=1;i<=n;++i)
if (a[i]+2*s[i]>=Max)
{
Max=a[i]+2*s[i];
maxp=i;
}
for (int i=1;i<=maxp;++i)
{
hp now;now.loc=i,now.val=a[i];
q.push(now);
}
for (int i=maxp+1;i<=n;++i)
{
hp now;now.loc=i,now.val=a[i]+s[i]*2;
p.push(now);
}
point=maxp+1;vis[maxp]=true;
ans[1]=Max;pt[1]=maxp;
for (int i=2;i<=n;++i)
{
hp l,r;l.val=l.loc=r.loc=r.val=0;
if (!q.empty()) l=q.top();
if (!p.empty()) r=p.top();
while (vis[l.loc])
{
l.val=l.loc=0;
if (!q.empty()) q.pop(),l=q.top();
}
while (vis[r.loc])
{
r.val=r.loc=0;
if (!p.empty()) p.pop(),r=p.top();
}
if (!r.val||(l.val!=0&&ans[i-1]+l.val>ans[i-1]+r.val-2*s[pt[i-1]]))
{
if (!q.empty()) q.pop();
vis[l.loc]=true;
pt[i]=pt[i-1];
ans[i]=ans[i-1]+l.val;
}
else
{
if (!p.empty()) p.pop();
vis[r.loc]=true;
pt[i]=r.loc;
ans[i]=ans[i-1]+r.val-2*s[pt[i-1]];
}
for (int j=point;j<=pt[i];++j)
{
hp now;now.loc=j,now.val=a[j];
q.push(now);
}
point=pt[i]+1;
}
for (int i=1;i<=n;++i) printf("%d\n",ans[i]);
}