HDU 5064 Find Sequence

本文介绍了一个涉及DP算法的问题,目标是在给定的整数序列中找出最长的非递减排列,同时确保相邻元素间的差值也呈非递减趋势。通过优化DP状态转移方程,将复杂度从O(n^3)降低到了O(n^2)。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目: LINK

这是BC上的题目,给你n个数a1, a2, ...., an. 这n个数的和为m(m<=2^22),要在里面取出尽可能多的数字(假设t个),组成新的序列b1, b2 ... bt.使得这个序列非递减,而且(b(i) - b(i-1))也是非递减的。求这个t的最大值。


题目没有告诉n的大小。我们先排序统计出大小不同的数字nn[], 和每个数字出现的次数mm[],可以算出不同的数字不会超过3000
dp[i][j] (j>=i) 表示以nn[i] 和nn[j]为所求序列的最末尾两个数字,这种情况下的序列的长度.
dp[i][i] = mm[i], dp[i][j] = max(dp[i][j], dp[k][i] + 1), (k<=i)
直接算的话复杂度O(n^3),不可取。我们可以发现上面的转移中随着j的增大k是随着减小的,可以优化到O(n^2).


#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <string>
#include <vector>
#include <cmath>
#include <queue>
#include <map>
#include <set>
using namespace std; 
#define INF 1000000000
//typedef __int64 LL; 
#define N 1011111
#define M 3000
int t, n, m, num[N], nn[M],mm[M],dp[M][M]; 
int main() 
{
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin); 
#endif // ONLINE_JUDGE
	scanf("%d", &t); 
	while(t--) {
		scanf("%d%d", &n, &m); 
		for(int i =1 ; i <= n; i ++) {
			scanf("%d", &num[i]); 
		}
		sort(num+1, num+1+n); 
		int tot = 0, cou = 1; 
		num[n+1] = -1; 
		for(int i = 2; i <= n+1; i++) {
			if(num[i] != num[i-1]) {
				tot ++; 
				nn[tot] = num[i-1]; 
				mm[tot] = cou; 
				cou = 1; 
			}
			else  cou++;  
		}
		int ans = 0; 
		for(int i = 1; i <= tot; i ++) {
			dp[i][i] = mm[i]; 
			ans = max(ans, dp[i][i]); 
			int k = i, ma = 0; 
			for(int j = i+1; j <= tot; j++) {
				while(nn[j] - nn[i] >= nn[i] - nn[k] && k>=1) {
					ma = max(ma, dp[k][i]); 
					k--; 
				}
				dp[i][j] = ma+1;
				ans = max(ans, dp[i][j]); 
			}
		}
		printf("%d\n", ans); 
	}
	return 0; 
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值