问题链接
问题:
给出一个物品在n个商店的不同价值,从第一个商店走到第n个商店
可以选择花钱买这个物品,也可以选择卖这个物品,但是身上只能带一个
问最后最多赚多少
输入
1. T组数据,
2 . n个商店, < 100000
3. 在n个商店的价值 v, v < int
输出
两个数,赚的钱 和 最少交易的次数
输入
1
5
9 10 7 6 8
输出
3 4
分析:
1. 如果 价值 是递增的, 那么,最后的 赚钱的最大值,一定是 a[ n ] - a[ 1 ] (假设所有的价值从a[1] 存到 a[ n ] )
因为只能带一个商品,那么第一次买入,一定选择最小的 a [ 1 ] , 最后一次卖出一定是最大的 a[ n ]!!!
中间不管怎么交易都会小于或等于这个值。。比如 ,a b c d (a < b < c < d)a 买 ,b卖,c买,d卖
ans = ( b - a) + (d - c) = ( d - a ) - ( c - d )...(c - d) > 0..
但是 如果 (a买 b卖)( b买 c卖)(c买 d卖) 这样
ans = (b - a)+(c - b)+( d - c ) = d - a ....
也就是说 赚没相邻两个商店的差价,最后的和就是最大赚钱值
2. 如果价值不是递增的。
那肯定是由许多个 递增的 小子序列 组成 的
把每一个递增的小子序列按 1 的思路求得ans 最后所有的ans相加。
a b c d ( b > a, c <= b, d > c , d > b) ---( 1 3 2 5 )
ans1 = d-a
ans2 = (b-a) + (d - c) = (d - a) + ( b - c ) .....( b - c) >= 0 ...所以ans2 是最优解
总结:
对于一个数列,只要相邻的两个价值可以赚钱,那就 ans += (a[ n + 1] - a[ n ])...
至于最少的交易次数。。。。。。
可以每一个商店做一个标记,每交易一次标记就 ++,也就是买入,标记++,卖出 ,标记++
那么标记最大值是 2 最小值是 0,
那么最后只把标记值是 1 的算上次数,也就是实际只在标记值是 1 ,的商店买入 或者 卖出。。。
但是这样有一个 bug。。。。。
比如:1 2 2 3. 应该是交易2次,但是按以上的算法是交易 4 次。
因为 2 2 的标记都是 1 , 但其实2 2 是不需要交易的。
也就是说,有相邻的数字是重复的话,会出现bug。。。
解决的方法很简单。。。只要在 输入的时候把相邻的重复筛掉,只留下一个,就ok了,
并不影响结果。
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+5;
struct Node
{
LL id;
LL v;
}a[MAXN];
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
LL n;
LL sum = 0;
LL cnt = 0;
memset(a,0,sizeof(a));
scanf("%lld",&n);
for (int i = 0; i < n; i++)
{
a[i].id = 0;
LL x;
scanf("%lld",&x);
if (x == a[i-1].v)
{
i--;
n--;
continue;
}
else
{
a[i].v = x;
}
}
for (int i = 0; i < n; i++)
{
if (a[i].v < a[i+1].v)
{
sum += a[i+1].v - a[i].v;
a[i].id ++;
a[i+1].id ++;
}
}
for (int i = 0; i < n; i++)
{
if (a[i].id == 1)
cnt ++;
}
cout << sum << " " << cnt <<endl;
}
return 0;
}