HOJ 3087 Discover's Problem I
2012-03-11 22:25
344 查看
Discover's Problem I
Submitted : 31, Accepted : 14Given a sequence , how to find the longest increasing subsequence? I think, almost all of you will think it's a piece of cake. Here comes a question about the increasing subsequence, and I think you will like it. Now you don't need to pay attention to the
length but to the sum of its elements. You should find out the increasing subsequence that the sum of its elements is max and print the sum of this increasing subsequence’s elements.
Input
The first line contains a integer T, indicating there a T cases(T<=10). Every case begin with a integer n, which is the length of the sequence. ( 1<=n<=10^5).The next line comes the elements . The values of it's elements are positive integers that no morethan 2^31-1.
Output
For every case, print the answer in a single line.Sample Input
2 5 100 1 2 2 3 5 9 3 4 10 5
Sample output
100 19
题目大意:给你一列数共n个(1<=n<=10^5),求最大的上升和序列。
分析:树状数组+DP 或则 线段树+DP现在我们先讲一下:树状数组+DP实际上状态转移方程是很容易想出的,dp[i]=max(dp[j])+a[i](其中0<j<i)关键是如何降低复杂度来实现快速的寻找最大的前i-1项中的最大上升和子序列。现在来说明一下如何用树状数组来实现快速的查询:按数的大小从小到大的排一下序,然后再按照数字的大小插入这样就保证了已经插入的就一定比插入的小,那么单调递增就能保证了,现在还一个需要确保,就是先后问题。由于树状数组如果按照排序前的序号插入的话,那么我们只统计他们的序号前面的就同样可以保证先后问题,仔细想一想其实没那么难的。
我们来寻找一下此问题的本源思想。我们是求上升且最大的子序列和,那么问题来了上升且最大,二这两个又不是单调的关系,无论怎样我们的快速查找的方法都只是一个排序的标准即一个判断条件。因此我们就想办法了,如果先确定一个不就OK了,寻找区间最大的方法是有的,因此我们就想方法先把单调升序列确定,然后查询区间的最大值。让序列在查询的过程中保持升序列的确很难想,现在介绍一下实际具体的做法:
1.设结构体,包含两个变量:数值,下标
2.按照数值从小到大的规则排序
3.遍历排序后的序列,按照结构体中的下标插入树状数组中:求出树状数组中插入位置前的最大的递升序列和,加上当前结构体中的数值再插入
4.遍历求出最大值关键是树状数组如何操作,下面还是不理解记住吧!
代码如下
/*
* File: main.cpp
* Author: Administrator
*
* Created on 2012年3月11日, 下午6:21
*/
#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAX = 100001;
long long a[MAX];
long long dp[MAX];
/*
* 这个是DP的思想,但是要实现DP还需一定的技巧
*/
int lowbit(int x) {
return x & (-x);
}
void add(int x, long long p) {
while (x < 100001) {
a[x] = max(p, a[x]);
x += lowbit(x);
}
}
long long sum(int x) {
long long res = 0;
while (x) {
res = max(res, a[x]);
x -= lowbit(x);
}
return res;
}
struct node {
int pos;
int element;
bool operator<(const node & a)const {
if (element != a.element) {
return element < a.element;
}
return pos > a.pos;
}
} Node[MAX];
int main() {
int T;
int n;
while (scanf("%d", &T) != EOF) {
while (T--) {
scanf("%d", &n);
memset(dp, 0, sizeof (dp));
memset(a, 0, sizeof (a));
for (int i = 1; i <= n; i++) {
scanf("%d", &Node[i].element);
Node[i].pos = i;
}
sort(Node + 1, Node + n + 1);
for (int i = 1; i <= n; i++) {
dp[Node[i].pos] = sum(Node[i].pos) + (long long)(Node[i].element);
add(Node[i].pos, dp[Node[i].pos]);
}
long long res = 0;
for (int i = 1; i <= n; i++) {
res = max(dp[i], res);
}
printf("%lld\n", res);
}
}
return 0;
}
相关文章推荐
- poj 3087 Shuffle'm Up
- jenkins里跑selenium webdriver,Chrome浏览器不能打开&&unknown error: unable to discover open pages
- G - Shuffle'm Up POJ 3087 模拟洗牌的过程,算作暴力搜索也不为过
- Count Color 线段树成段更新 hoj &poj
- Shuffle'm Up poj 3087
- poj-3087-Shuffle'm Up-模拟
- POJ 3087 Shuffle'm Up
- POJ 3087 Shuffle'm Up
- Hoj 2010 GCD & LCM Inverse
- POJ 3087 Shuffle'm Up(简单模拟)
- 3087_Shuffle'm Up
- poj 3087 Shuffle'm Up
- POJ 3087 Shuffle'm Up模拟
- POJ 3087 Shuffle'm Up(DFS 循环)
- [数论]HOJ 2010 GCD & LCM Inverse
- HOJ 12058 Judges' Time Calculation 解题报告
- upnpDiscover( ) :"sendto: Operation not permitted" && getaddrinfo() error : “Bad value for ai_flags”
- 【poj 3087】 Shuffle'm Up 题意&题解&代码(C++)
- Poj 3087 Shuffle'm Up 【BFS】
- POJ3087 Shuffle'm Up 简单模拟