题目链接:传送门
题目大意:
你要按照顺序依次经过n个商店,每到达一个商店你可以购买一件商品,也可以出售你手中的商品。
同一时刻你手上最多拿一件商品。在第i个商店购买和出售的代价都是a[i]。
问你经过完n个商店后的最大收益。
同时,在最大化收益的前提下,求最小的交易次数。
题目思路:
做法一:DP
dp[i][0/1]表示已经访问完了i个商店,你手中是否有商品,此时的最大收益。1代表手上有商品,0代表没有
num[i][0/1]表示当dp[i][j]取最大值时最少的交易次数。
做法二:贪心
首先,如果a[i]=a[i+1],则可以删掉第i+1个商店。因为任何在第i+1个商店进行的交易都可以转为在第i个商店进行,且收益不变。之后,如果a[i]<a[i+1],则离开第i个商店时一定要带上一件商品。如果a[i]>a[i+1],则离开第i个商店时一定要空着手。
这样,第一问的答案就为,第二问的答案就为长度>1的极大递增连续段的数量。
做法一代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
long long dp[maxn][2];
int num[maxn][2];
long long a[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%lld",&a[i]);
memset(dp,0,sizeof dp);
memset(num,0,sizeof num);
dp[0][1]=-a[1];
num[0][1]=1;
for(int i=1;i<=n;i++)
{
if(dp[i-1][1]>=dp[i-1][0]-a[i])
{
dp[i][1]=dp[i-1][1];
if(dp[i-1][1]==dp[i-1][0]-a[i])
{
num[i][1]=min(num[i-1][1],num[i-1][0]+1);
}
else
{
num[i][1]=num[i-1][1];
}
}
else
{
dp[i][1]=dp[i-1][0]-a[i];
num[i][1]=num[i-1][0]+1;
}
if(dp[i-1][0]>=dp[i-1][1]+a[i])
{
dp[i][0]=dp[i-1][0];
if(dp[i-1][0]==dp[i-1][1]+a[i])
{
num[i][0]=min(num[i-1][0],num[i-1][1]+1);
}
else
{
num[i][0]=num[i-1][0];
}
}
else
{
dp[i][0]=dp[i-1][1]+a[i];
num[i][0]=num[i-1][1]+1;
}
}
cout<<dp[n][0]<<" "<<num[n][0]<<endl;
}
return 0;
}
做法二的代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn=100000+10;
long long a[maxn];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
int n;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%lld",&a[i]);
}
long long ans=0;
int num=0;
int cnt=1;
for(int i=1;i<n;i++)
{
ans+=max(a[i+1]-a[i],(long long)0);
if(a[i+1]>a[i])
{
cnt++;
}
else if(a[i+1]<a[i]&&cnt>1)
{
num+=2;
cnt=1;
}
}
if(cnt>1)
{
num+=2;
}
printf("%lld %d\n",ans,num);
}
return 0;
}
/*
1
5
9 10 7 6 8
3 4
*/