ZSC 1317 土豪金上的标号 (LIS + 最大连续子序列和)

Description

在光头强的帮助下,熊大熊二欢欢喜喜在Acmer那里领了一大堆土豪金回来,
但光头强却手拿猎枪在前面挡着,眼睛瞪大着惊喜说道:“哇!!好闪的土豪金啊!!哈哈哈,发财了,笨狗熊赶紧把我的土豪金放下!!”
熊大不服了:“我们也费了老大劲才得到的,怎么能就这样给你。”
熊二附和着:“就是就是。”
光头强低头沉思了一下:“嗯,说得也对,那好吧,笨狗熊,你们看,这土豪金上面都有一个标号,我把这些土豪金排个顺序,熊二,你要是能找到连续的几个土豪金上面的标号总和最大….”
这时熊二立刻插嘴:“这几个就是我的了!!”
光头强拿枪晃了晃:“NO,NO,臭狗熊,听着,你要告诉我标号总和最大是多少,要是正确,那么在此基础上,你可以在标号总和最大的那几个土豪金里面按顺序选几个,但你选出来的土豪金的标号必须是严格递增的,这样你才能拿走,嘻嘻嘻嘻!!”
熊二急了:“熊大,怎么办?我不会啊!”熊大插着腰喊:“可恶的光头强,熊二别急,看我的。”于是熊二大手一挥,抓住低头路过的你:“来,小子,帮我解决问题!”

Input

输入将包含多个测试数据,第一行一个T(T<20),代表多少组数据。接下来T行,每行的第一个数n(n<100000)代表熊大熊二有多少个土豪金,然后是n个数,表示土豪金上的标号。

Output

输出两个数,第一个数代表标号和最大,第二个数代表熊二能拿走多少个土豪金;

Sample Input

2
4 1 2 3 1
5 5 4 3 2 1

Sample Output

7 3
15 1

题解:

最大连续子序列和的状态转移方程:dp(i) = max(dp(i - 1)+a[i], a(i));
LIS状态转移方程:lis(i) = max(j), j = 0, 1, 2…i, lis(j) <= lis(i);

坑1,先找出最大的连续子序列和,注意这个子序列可能有多个
坑2,在坑1找出的基础上,找出最长上升子序列

另外此题LIS只能用nlogn的算法,时间卡n2

#include <cstdio>
#include <algorithm>
using namespace std;
const int MAXN = 100000 + 10;
const int INF = 0x3f3f3f3f;
int t, n, maxLen, a[MAXN], dp[MAXN], lis[MAXN], maxSum;

int Lis(int l, int r) {
  lis[1] = a[l];
  int len = 1;
  for (int i = 1; i <= r - l; ++i) {
    int j = lower_bound(lis + 1, lis + 1 + len, a[i + l]) - lis;
    if (len < j) { len = j; }
    lis[j] = a[i + l];
  }
  return len;
}

int main() {
  scanf("%d", &t);
  while (t--) {
    scanf("%d", &n);
    maxSum = -INF;
    maxLen = 0;
    int l = 1;
    for (int i = 1; i <= n; ++i) {
      scanf("%d", &a[i]);
      if (dp[i - 1] + a[i] >= a[i]) { dp[i] = dp[i - 1] + a[i]; } 
      else { dp[i] = a[i]; l = i; }

      if (maxSum < dp[i]) { maxSum = dp[i]; maxLen = Lis(l, i); } 
      else if (maxSum == dp[i]) { maxLen = max(maxLen, Lis(l, i)); }
    }
    printf("%d %d\n", maxSum, maxLen);
  }
  return 0;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值