华师一附中OI组
标题:
P2234 [HNOI2002]营业额统计
[打印本页]
作者:
admin
时间:
2020-4-5 18:58
标题:
P2234 [HNOI2002]营业额统计
https://www.luogu.com.cn/problem/P2234
题目描述
Tiger最近被公司升任为营业部经理,他上任后接受公司交给的第一项任务便是统计并分析公司成立以来的营业情况。
Tiger拿出了公司的账本,账本上记录了公司成立以来每天的营业额。分析营业情况是一项相当复杂的工作。由于节假日,大减价或者是其他情况的时候,营业额会出现一定的波动,当然一定的波动是能够接受的,但是在某些时候营业额突变得很高或是很低,这就证明公司此时的经营状况出现了问题。经济管理学上定义了一种最小波动值来衡量这种情况:
当最小波动值越大时,就说明营业情况越不稳定。
而分析整个公司的从成立到现在营业情况是否稳定,只需要把每一天的最小波动值加起来就可以了。你的任务就是编写一个程序帮助Tiger来计算这一个值。
第一天的最小波动值为第一天的营业额。
该天的最小波动值=min{|该天以前某一天的营业额-该天营业额|}。
输入格式
输入由文件’turnover.in’读入。
第一行为正整数n(n<=32767) ,表示该公司从成立一直到现在的天数,接下来的n行每行有一个整数ai(|ai|<=1000000) ,表示第i天公司的营业额,可能存在负数。
输出格式
输出文件仅有一个正整数,即Sigma(每天最小的波动值) 。结果小于2^31 。
输入输出样例
输入 #1复制
6
5
1
2
5
4
6
输出 #1复制
12
说明/提示
结果说明:5+|1-5|+|2-1|+|5-5|+|4-5|+|6-5|=5+4+1+0+1+1=12
作者:
admin
时间:
2020-4-5 19:00
此题也是好题,十几年前的好题,可能比你们年纪还大,有多种方法:
1、线段树可以吧,设每天的营业额在线段树数组中的下标为他本身的值
然后每次输入一个数时我们先在这个数的左边的区间查找最大值
再在右边的区间查找最小值
(这意味着我们要找比这个数小的最大值和比这个数大的最小值)
然后比较两者取差的绝对值最小的加到Ans里即可
2、BST可以吧,为了怕退化成一条链,分别试试splay和treap(能不能treap呀)
作者:
admin
时间:
2020-4-5 19:12
先来个STL版的,因为是十几年的题目,所以在现在的机器上居然应跑过了。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<set>
#define inf 0x3f3f3f3f3f3f3fll
using namespace std;
set<long long> s;
set<long long>::iterator l,r;
long long a,res;
int n,i;
int main()
{
s.insert(inf);
s.insert(-inf);
cin>>n>>res;
s.insert(res);
for(i=2; i<=n; i++)
{
cin>>a;
l=r=s.lower_bound(a);
l--;
if(*r-a < a-*l)res+=*r-a;
else res+=a-*l;
s.insert(a);
}
cout<<res;
return 0;
}
复制代码
作者:
admin
时间:
2020-4-11 13:05
先来一个基本的BST,不带任何调整的,锻炼下插入和查找,交上去,还得了70分,不错,说明基本功还在,出题人显然也考虑到了。况且只是十几年前的,当时的电脑还没有现在这么快!
#include<bits/stdc++.h>
using namespace std;
const int inf=0x3FFFFFFF;
const int N=100100;
struct node
{
int val,cnt,s[2];
} a[N];
int n,x,ans,tot,root;
void BSTPr(int rt)
{
if (a[rt].s[0]>0) BSTPr(a[rt].s[0]);
cout<<a[rt].val<<' ';
if (a[rt].s[1]>0) BSTPr(a[rt].s[1]);
}
void Ins(int & rt,int x)
{
if (rt==0)
{
rt=++tot;
a[rt].val=x;
a[rt].cnt=1;
}
else if (a[rt].val==x) a[rt].cnt++; ///其实可以不要
else
{
int k=a[rt].val<x;/// k=0 表示左
Ins(a[rt].s[k],x);
}
}
int Find(int rt,int x)
{
if (rt==0) return 0;
if (a[rt].val==x) return rt;
int k=a[rt].val<x; /// k=0表示左子树中去1表示去右子树
return Find(a[rt].s[k],x);
}
int Pre(int rt, int x)
{
if(rt==0) return 0;
if(a[rt].val>=x) return Pre(a[rt].s[0],x);//递归查找左子树
else
{
int t=Pre(a[rt].s[1],x);
if (t==0) return rt;
else if (a[t].val<a[rt].val) return rt;//找右子树中是否存在前驱
else return t;
}
}
int Suc(int rt, int x) ///大于x的最小
{
int p=rt, ans=0;
while(p>0)
{
if(a[p].val<=x) p=a[p].s[1];
else
{
ans=p;
p=a[p].s[0];
}
}
return ans;
}
int main()
{
cin>>n>>x;
ans=x,root=1,tot=1,a[1].val=x;
int p0,p1,p2,x1,x2;
for(int i=2; i<=n; i++)
{
///BSTPr(root);
cin>>x;
p0=Find(root,x);
if (p0==0)
{
p1=Pre(root,x);
p2=Suc(root,x);
x1=x2=inf;
if (p1>0) x1=(x-a[p1].val);
if (p2>0) x2=(a[p2].val-x);
ans+=min(x1,x2);
Ins(root,x);
}
}
cout<<ans;
return 0;
}
复制代码
作者:
admin
时间:
2020-4-11 13:11
再锻炼下自己,把查找前驱和后继改一下,前驱包含自己,也就是说找小于等于自己的最大数,
作者:
admin
时间:
2020-4-11 13:11
杯水车薪还是过不了,上一个替罪羊看看,其实意义不大
作者:
admin
时间:
2020-4-11 13:12
来一发treap,这次使用了splay里面的那种旋转方法。
作者:
admin
时间:
2020-4-11 13:12
来一个splay吧,有点大材小用的感觉。
欢迎光临 华师一附中OI组 (http://hsyit.cn/)
Powered by Discuz! X3.2