思维杂题
思维杂题
Buy Low Sell High
最简单的贪心:买入最小的股票 在可以盈利的当天卖出
那么这个在递减数据下是正确的 但是在递增数据下显然是错的 如 \(1\ 2\ 100\)
如果贪心 我们只会在 \(1\) 节点买入并在 \(2\) 节点卖出 获得 \(1\) 的贡献
但是实际上我们可以将 \(1\) 股票在 \(100\) 的时候卖出来获得更多贡献
那么我们考虑反悔贪心:
如果买了 因为是用小根堆贪心 就是一定最优的 直接出队
我们对于第 \(i\) 天买到第 \(j\) 天卖的操作 价值为 \(v_j-v_i\)
那么我们现在要实现反悔操作 就需要入队一个值 \(val\) 使得如果第 \(i\) 天买到第 \(k\) 天卖 价值更优
相当于是答案要加上 \(v_k-val+(v_j-v_i)=v_k-v_i\) 解得 \(val=a_j\) 所以如果我们可以卖 那么需要多推入队列中一个数来实现反悔
反悔之后 \(j\) 点从 \(2\) 个变成 \(1\) 个 显然 \(j\) 点相当于空出来了 可以进行下一次操作 符合我们的设计
相当于是用每个点在队列内部的数量来表示该点的状态
\(0\) 个为买了 \(1\) 个为不操作 \(2\) 个为卖了
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
int read ()
{
int x = 0 , f = 1;
char ch = cin.get();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = cin.get(); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = cin.get(); }
return x * f;
}
int n , ans;
priority_queue < int,vector<int>,greater<int> > q;
signed main ()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
for ( int i = 1 ; i <= n ; i ++ )
{
int x = read();
if ( !q.empty() && q.top() < x ) ans += x - q.top() , q.pop() , q.push(x);
q.push(x);
}
cout << ans << endl;
return 0;
}
P4552 [Poetize6] IncDec Sequence
考虑差分数组
显然查分数组有正有负 那么最优操作应该将一个正数减掉 \(1\) 再将一个负数加上 \(1\) 这样一次能操作两个 是最优情况
那么最小操作次数就是正数和负数中间的最大值
结果数即为所有单独修改一个的操作+1 (因为可以将前面的往上加 也可以将后面的往下减)
#include <bits/stdc++.h>
using namespace std;
#define inl inline
#define int long long
const int N = 1e6 + 5;
inl int read ()
{
int x = 0 , f = 1;
char ch = getchar();
while ( !isdigit ( ch ) ) { if ( ch == '-' ) f = -1; ch = getchar (); }
while ( isdigit ( ch ) ) { x = ( x << 1 ) + ( x << 3 ) + ( ch ^ 48 ); ch = getchar (); }
return x * f;
}
int n , a[N] , zheng , fu , cha[N];
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0) , cout.tie(0);
n = read();
a[1] = read();
for ( int i = 2 ; i <= n ; i ++ )
{
a[i] = read() , cha[i] = a[i] - a[i-1];
if ( cha[i] > 0 ) zheng += cha[i];
else fu += ( - cha[i] );
}
// for ( int i = 1 ; i <= n ; i ++ ) cout << cha[i] << ' ';
// cout << endl;
cout << max ( zheng , fu ) << endl;
cout << abs ( zheng - fu ) + 1 << endl;
return 0;
}