1.最大连续子序列之和
时间限制:C/C++语言 1000MS;其他语言 3000MS
内存限制:C/C++语言 65536KB;其他语言 589824KB
题目描述:
给定K个整数的序列{ N1, N2, …, NK },其任意连续子序列可表示为{ Ni, Ni+1, …, Nj },其中 1 <= i <= j <= K。最大连续子序列是所有连续子序中元素和最大的一个, 例如给定序列{ -2, 11, -4, 13, -5, -2 },其最大连续子序列为{ 11, -4, 13 },最大和为20
输入:
一个整数数组
输出:
最大的和
样例:
输入:
1 2 3
输出:
6
思路:
动态规划经典例题。
dp[i]代表,使用了num[i]的子序列,最大和为多少。
既然dp[i]使用了num[i],那么dp[i+1]即为使用num[i+1],则这个子序列要么只有num[i+1]一个数,要么从上一个使用了num[i]的子序列接过来。(只要是非负数,怎么拿都不亏,负数才会出现问题)
∴dp[i] = max( dp[i-1]+num[i] , num[i])
代码:
#include <cstdio>
#include <string>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
int dp[100010];
int a[100010];
int n;
int split(string &s,int a[])
{
int n = 0;
int res = 0;
int k = 1;
s += ' ';
for(int i=0;i<s.size();i++)
{
if(s[i]=='-')
{
k = -1;
continue;
}
if('0'<=s[i] && s[i]<='9')
{
res = res*10 + s[i]-'0';
}
else
{
a[++n] = k*res;
res = 0;
k = 1;
}
}
return n;
}
int main()
{
string input;
getline(cin,input);
n = split(input,a);
for(int i=1;i<=n;i++)
dp[i] = max(0,a[i]);
int max_num = 0;
for(int i=1;i<=n;i++)
{
dp[i] = max(dp[i-1]+a[i],dp[i]);
max_num = max(max_num,dp[i]);
}
cout<<max_num<<endl;
return 0;
}
A了。难点在处理输入。
2.利润最大化
时间限制:C/C++语言 1000MS;其他语言 3000MS
内存限制:C/C++语言 65536KB;其他语言 589824KB
题目描述:
米兔是一个投资人,持有着小米的股票。股票价格每日都有波动,数组price代表了每日股票的具体价格,其中price[i]代表小米在第i天的股价。米兔最多可以进行两次交易(一个买进,卖出为一次交易)并且不能同时进行两次交易(必须在再次购买前出售掉之前的股票),米兔想知道他最多能够获得多少利润呢?
输入:
正整数序price,代表了股票价格。其中第i个数代表了第i天的价格。
输出:
两次交易后能获得的最大利润
样例:
输入:
2 1 5 0 2 3 1 4
输出:
8
思路:
枚举中间分隔,两头分别用前缀最小和后缀最大,最后再看看有没有只交易一轮的。其实一开始以为要开线段树来拿区间极值,写完线段树后发现用不上。这个算法效率不高,基本相当于暴力。
代码:
#include <cstdio>
#include <string>
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXNUM = 100010;
int a[MAXNUM];
int n;
int split(string &s,int a[])
{
int n = 0;
int res = 0;
int k = 1;
s += ' ';
for(int i=0;i<s.size();i++)
{
if(s[i]=='-')
{
k = -1;
continue;
}
if('0'<=s[i] && s[i]<='9')
{
res = res*10 + s[i]-'0';
}
else
{
a[++n] = k*res;
res = 0;
k = 1;
}
}
return n;
}
int dp[MAXNUM],min_v[MAXNUM],max_v[MAXNUM];
int main()
{
string input;
getline(cin,input);
n = split(input,a);
int max_num = 0;
memset(min_v,0x3f,sizeof(min_v));
for(int i=1;i<=n;i++)
min_v[i] = min(a[i],min_v[i-1]);
for(int i=n;i>=1;i--)
max_v[i] = max(a[i],max_v[i+1]);
for(int key=2;key<=n-2;key++)//枚举中间
{
int tempL = 0;
for(int i=1;i<=key;i++)
{
tempL = max(tempL, a[i]-min_v[i]);
}
int tempR = 0;
for(int i=n;i>=key+1;i--)
{
tempR = max(tempR, max_v[i]-a[i]);
}
max_num = max(max_num, tempL+tempR);
}
for(int i=1;i<=n;i++)
{
max_num = max(max_num, a[i]-min_v[i]);
}
cout<<max_num<<endl;
return 0;
}
A了,不知道数据范围有多少,这个应该是O(n²)的。笑死我了,一开始写了4重for循环O(n^4)的,竟然能过77%。
int max_num = 0;
for(int i=1;i<=n-1;i++)
for(int j=i+1;j<=n;j++)
for(int k=j;k<=n;k++)
for(int l=k+1;l<=n;l++)
max_num = max(max_num,a[j]-a[i] + a[l]-a[k]);
cout<<max_num<<endl;