MYF

HDU 5125 magic balls

题目链接

HDU 5125

题目类型:LIS变形

题目来源:BestCoder Round #20

题目分析

题目大意

$n$个人站成一排,每个人有两个容器$a, b$,巫师可以交换某一个人手里两个容器的容积,每交换一次消耗一点魔力值,巫师的魔力值有限,问在他能力范围之内,使$n$个人手中的$a$容器所形成的最长上升子序列长度最大,问最大长度是多少

解析

对于$n$个点,每个点具有两个状态,分别表示含有当前$a$容器以及含有当前$b$容器所形成的最长上升子序列信息,信息存储到该点所消耗的魔力值以及长度,对于不同容器,消耗的魔力值不一样,对于$b$容器,花费的魔力值要增加$1$点,如果对于$a$容器,花费的魔力值等于上一个状态的魔力值,这样我们可以求出来以任意一个容器结尾(必然包含该容器)的最长上升子序列的长度以及花费。我们找到最长的且花费在巫师能力值范围之内的即可。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <set>
#include <map>
#include <stack>
#include <cmath>
#include <queue>
#include <cstdio>
#include <string>
#include <vector>
#include <iomanip>
#include <bitset>
#include <cstring>
#include <iostream>
#include <deque>
#include <algorithm>
#define Memset(a,val) memset(a,val,sizeof(a))
#define PI acos(-1)
#define PB push_back
#define MP make_pair
#define rt(n) (i == n ? '\n' : ' ')
#define hi printf("Hi----------\n")
#define IN freopen("input.txt","r",stdin);
#define OUT freopen("output.txt","w",stdout);
#define debug(x) cout<<"Debug : ---"<<x<<"---"<<endl;
#define debug2(x,y) cout<<"Debug : ---"<<x<<" , "<<y<<"---"<<endl;
#pragma comment(linker, "/STACK:1024000000,1024000000")
using namespace std;
typedef pair<int,int> PII;
typedef long long ll;
const int mod=110119;
const int maxn=1e5+5;
const int INF=0x3f3f3f3f;
const double eps=1e-8;
struct node{
int len, cost;
}dp[2005];
int a[2005];
int main(){
int t;
scanf("%d",&t);
while (t--) {
int n,m,isEven;
scanf("%d%d",&n,&m);

//对于a[i] 若i为奇数,则对应第i/2+1个人的a容器 若i为偶数则对应第i/2个人手里的b容器
for (int i=1; i<=2*n; i++) scanf("%d",&a[i]);

dp[1].len = 1; dp[1].cost = 0;
dp[2].len = 1; dp[2].cost = 1;

int pos = 1;
for (int i=3; i<=2*n; i++) {
isEven = i % 2 ? 0 : 1;
dp[i].len= 1;
dp[i].cost = isEven;

//如果当前为下标为奇数对应a容器直接从上一位开始往前找即可,否则对应b容器,要跳过当前人的a容器,所以要往前跳两位开始搜索
for (int j=i-1-isEven; j>=1; j--) {
if (a[j]<a[i]) {
if (dp[j].len + 1 > dp[i].len) {
dp[i].len = dp[j].len + 1;
dp[i].cost = dp[j].cost + isEven;
}
else if (dp[i].len == dp[j].len + 1 && dp[i].cost > dp[j].cost + isEven)
dp[i].cost = dp[j].cost + isEven;
}
}

// 更新结果下标
if (dp[i].len > dp[pos].len && dp[i].cost <= m) pos = i;
}
printf("%d\n",dp[pos].len);
}
}