1. 程式人生 > >【codevs 5126】[NOIP2015 普及組T4]推銷員(貪心)

【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]);
}