Increasing Speed Limits hdu3030 树状数组求一个序列中有多少个上升子序列

本文介绍了一种使用树状数组求解最长上升子序列(LIS)问题的算法模板,通过实例演示了如何利用树状数组进行更新和查询操作,以高效地找到序列中最长的递增子序列。

http://acm.hdu.edu.cn/showproblem.php?pid=3030

首先来个树状数组求最长上升子序列的模板

~~~c
#include <cstdio>
#include <algorithm>
using namespace std;

#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define maxN 10005
int n, L, v[maxN], a[maxN], T[maxN];

void update(int i, int x) { 
  for (; i <= L; i += i & -i)
    T[i] = max(T[i], x);
}
int query(int i) {
  int ans = 0;
  for (; i; i -= i & -i)
    ans = max(ans, T[i]);
  return ans;
}
int main () {
  scanf("%d", &n);
  FOR(i, 0, n - 1) scanf("%d", &v[i]), a[i] = v[i];
  sort(a, a + n);
  L = unique(a, a + n) - a;
  int ans = 1, t;
  FOR(i, 0, n - 1) {
    int p = lower_bound(a, a + L, v[i]) - a + 1;
    t = query(p - 1) + 1;
    ans = max(ans, t);
    update(p, t);
  }
  printf("%d\n", ans);
  return 0;
}

把求最大值改成求和就可以求上升子序列的个数

~~~c
#include <cstdio>
#include <algorithm>
using namespace std;

#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define maxN 10005
int n, L, v[maxN], a[maxN], T[maxN];

void update(int i, int x) { 
  for (; i <= L; i += i & -i)
    T[i] = max(T[i], x);
}
int query(int i) {
  int ans = 0;
  for (; i; i -= i & -i)
    ans = max(ans, T[i]);
  return ans;
}
int main () {
  scanf("%d", &n);
  FOR(i, 0, n - 1) scanf("%d", &v[i]), a[i] = v[i];
  sort(a, a + n);
  L = unique(a, a + n) - a;
  int ans = 1, t;
  FOR(i, 0, n - 1) {
    int p = lower_bound(a, a + L, v[i]) - a + 1;
    t = query(p - 1) + 1;
    ans = max(ans, t);
    update(p, t);
  }
  printf("%d\n", ans);
  return 0;
}
在C语言中,可以使用动态规划的方法来找到一个整数数组中的最长递增子序列(LIS)。这里是一个简单的分治算法示例: ```c #include <stdio.h> #include <stdlib.h> // 动态规划函数,lis[i]表示arr[0...i]中最长递增子序列的长度 int lis(int arr[], int n) { int *lis = (int*)malloc((n + 1) * sizeof(int)); // 初始化lis数组 lis[0] = 1; // 最小长度为1 for (int i = 1; i < n; i++) { // 遍历输入数组 int max_len = 0; for (int j = 0; j < i; j++) { // 比较当前元素与之前的所有元素 if (arr[j] < arr[i] && lis[j] > max_len) max_len = lis[j]; } lis[i] = max_len + 1; // 更新lis值,如果当前元素比之前的元素大,则可能形成新的LIS } int result = 0; // 最终的结果是最长递增子序列的长度 for (int i = 0; i <= n; i++) if (result < lis[i]) result = lis[i]; printf("Length of longest increasing subsequence is %d\n", result); // 输出最长子序列的过程 int tail = result - 1; // 当前最远的索引 while (tail >= 0) { printf("%d ", arr[tail]); tail = lis[tail] - 1; // 回溯到lis[tail]的位置 } printf("\n"); free(lis); // 释放内存 return result; } int main() { int arr[] = {10, 9, 2, 5, 3, 7, 101, 18}; int n = sizeof(arr) / sizeof(arr[0]); lis(arr, n); return 0; } ``` 当你运行这个程序,它会输出给定数组中最长的递增子序列及其长度。注意,这个代码仅能输出最长子序列,如果你需要完整的子序列元素,可以在`while`循环中追加回溯过程。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值