【水题】NOIP201504推销员

NOIP201504推销员

【问题描述】  

    阿明是一名推销员,他奉命到螺丝街推销他们公司的产品。螺丝街是一条死胡同,出口与入口是同一个,街道的一侧是围墙,另一侧是住户。螺丝街一共有 N 家住户,第 i 家住户到入口的距离为 Si 米。由于同一栋房子里可以有多家住户,所以可能有多家住户与入口的距离相等。阿明会从入口进入,依次向螺丝街的 X 家住户推销产品,然后再原路走出去。阿明每走 1 米就会积累 1 点疲劳值,向第 i 家住户推销产品会积累 Ai 点疲劳值。阿明是工作狂,他想知道,对于不同的 X,在不走多余的路的前提下,他最多可以积累多少点疲劳值。

【输入格式】  

第一行有一个正整数 N,表示街住户数量,接下来一行有 N 个正整数,其中第 i 个整数 Si 表示第 i 家住户到入口距离保证 S1<=S2<=S3....<10 的 8 次方。接下来一行有 N 个整数,其中第 i 个整数 Ai 表示向第 i 个住户推销产品会积累疲劳值。保证 Ai<=10 的 3 次方。

 

【输出格式】  

输出 N 行,每行一个正整数,其中第 i 行整数表示当 x=i,阿明积累的疲劳值。

 

【输入样例】    

5
1 2 3 4 5
1 2 3 4 5

 

【输出样例】

15
19
22
24
25

 

【数据规模与约定】

数据范围:1<= N <= 100000。

 

【试题分析】

     不会做?会暴力吗?普通来说60分做法,100分其实一点也没问题!设一个结构体每次按优先级排序就可以了,想不到学校OJ都有那么多人抄的集训队爷的代码……

    NOIP的数据水,在洛谷等oj上过了官方样例,但是没有过老师加上的样例……

    不过放心,这是改了在学校OJ上AC的代码……

    并木有线段树等等高深算法……

    暴力搞定一切……

【代码】

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm> 
using namespace std;
inline long long read()
{
	long long x=0,f=1;char c=getchar();
	for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
	for(;isdigit(c);c=getchar()) x=x*10+c-'0';
	return x*f;
}
struct data
{
	long long num;//num为推销第i家推销花费的精力
	long long k;//k为第i家距镇口的距离
	long long f;//f为只对第i家进行推销的花费经历
}a[100001];
bool cmp(data a,data b)
{
	return a.k<b.k;
}
bool cmp1(data a,data b)
{
	return a.f>b.f;
}
bool cmp2(data a,data b)
{
	return a.num>b.num;
} 
long long n,trueto[100001];//true数组记录是否选择过,其实完全可以不要
int main()
{
    n=read();
    for(long long i=1;i<=n;i++) a[i].k=read();
    for(long long i=1;i<=n;i++) a[i].num=read();
    sort(a+1,a+n+1,cmp);//先按距村口远近排序
    long long sum=0;
    for(long long i=1;i<=n;i++) a[i].f=(a[i].k*2)+a[i].num;//计算f
    sort(a+1,a+n+1,cmp1);//对f进行排序
    long long ans=a[1].f;//第一个要最大一定要选单独推销精力最大的一家
    long long temp=a[1].k,tmp2,temp2=a[1].num;//记录,方便后面查找
    cout<<ans<<endl;//第一个输出
    sort(a+1,a+n+1,cmp2);//按num排序,因为当选择了这家以后比它距村口近的只需要加上推销的经历
	for(int i=1;i<=n;i++) if(a[i].k==temp&&ans==a[i].f&&temp2==a[i].num) {trueto[i]=1;tmp2=i;break;}//记录我们原先找到f的地方进行标记 
    for(long long i=1;i<=n;i++)
    {
	    if(trueto[i]) continue;//其实只有上面的f跳过
    	long long maxn=a[i].num;
    	long long tmp=i;
		trueto[tmp]=1;
		if(a[tmp].k<=temp)ans+=a[tmp].num;//如果距村口比最大的距离短那么只需要加上这个精力
		else ans-=(a[tmp2].k*2),tmp2=tmp,temp=a[tmp].k,ans+=a[tmp].f;//要去掉原先最大的的路程计算,然后要加上这一次的
		printf("%lld\n",ans);//输出
    }
}
posted @ 2016-09-26 21:34  wxjor  阅读(501)  评论(1编辑  收藏  举报