程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> C++ >> C++入門知識 >> hdu45221——小明系列問題——小明序列 線段樹優化dp

hdu45221——小明系列問題——小明序列 線段樹優化dp

編輯:C++入門知識

hdu45221——小明系列問題——小明序列 線段樹優化dp


小明系列問題——小明序列

Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1918 Accepted Submission(s): 583


Problem Description   大家都知道小明最喜歡研究跟序列有關的問題了,可是也就因為這樣,小明幾乎已經玩遍各種序列問題了。可憐的小明苦苦地在各大網站上尋找著新的序列問題,可是找來找去都是自己早已研究過的序列。小明想既然找不到,那就自己來發明一個新的序列問題吧!小明想啊想,終於想出了一個新的序列問題,他欣喜若狂,因為是自己想出來的,於是將其新序列問題命名為“小明序列”。

  提起小明序列,他給出的定義是這樣的:
  ①首先定義S為一個有序序列,S={ A1 , A2 , A3 , ... , An },n為元素個數 ;
  ②然後定義Sub為S中取出的一個子序列,Sub={ Ai1 , Ai2 , Ai3 , ... , Aim },m為元素個數 ;
  ③其中Sub滿足 Ai1 < Ai2 < Ai3 < ... < Aij-1 < Aij < Aij+1 < ... < Aim ;
  ④同時Sub滿足對於任意相連的兩個Aij-1與Aij都有 ij - ij-1 > d (1 < j <= m, d為給定的整數);
  ⑤顯然滿足這樣的Sub子序列會有許許多多,而在取出的這些子序列Sub中,元素個數最多的稱為“小明序列”(即m最大的一個Sub子序列)。
  例如:序列S={2,1,3,4} ,其中d=1;
  可得“小明序列”的m=2。即Sub={2,3}或者{2,4}或者{1,4}都是“小明序列”。

  當小明發明了“小明序列”那一刻,情緒非常激動,以至於頭腦凌亂,於是他想請你來幫他算算在給定的S序列以及整數d的情況下,“小明序列”中的元素需要多少個呢?

Input   輸入數據多組,處理到文件結束;
  輸入的第一行為兩個正整數 n 和 d;(1<=n<=10^5 , 0<=d<=10^5)
  輸入的第二行為n個整數A1 , A2 , A3 , ... , An,表示S序列的n個元素。(0<=Ai<=10^5)
Output   請對每組數據輸出“小明序列”中的元素需要多少個,每組測試數據輸出一行。
Sample Input
2 0
1 2
5 1
3 4 5 1 2
5 2
3 4 5 1 2

Sample Output
2
2
1

Source 2013騰訊編程馬拉松初賽第四場(3月24日)
Recommend liuyiding | We have carefully selected several similar problems for you: 5137 5136 5135 5134 5133

Statistic | Submit | Discuss | Note


這道題唯一的看點就在n的范圍很大以至於暴力會超時

狀態方程很好想,dp[i] = max(dp[j] + 1)其中a[i] > a[j]

我們把以第i個元素為結尾的最長上升子序列放到線段樹對應值為a[i]的葉子上(有點hash思想,這是為了保證上升這個特性,查詢的時候方便),當然如果此時的i-d<=1就不用插入了,這時候用不到任何的前置狀態。

需要用我們就插入一次,而且每次插入我們都能保證那個點和當前點i的距離一定大於d(之前已經空了d個位置),到時就直接去線段樹上小於a[i]的區間找最大值就行了


#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

const int N = 100010;

int dp[N];
int arr[N];
struct node
{
	int l, r;
	int val;
}tree[N << 2];

void build(int p, int l, int r)
{
	tree[p].l = l;
	tree[p].r = r;
	tree[p].val = 0;
	if (l == r)
	{
		return;
	}
	int mid = (l + r) >> 1;
	build(p << 1, l, mid);
	build(p << 1 | 1, mid + 1, r);
}

void update(int p, int pos, int val)
{
	if (tree[p].l == tree[p].r)
	{
		tree[p].val = val;
		return;
	}
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (pos <= mid)
	{
		update(p << 1, pos, val);
	}
	else
	{
		update(p << 1 | 1, pos, val);
	}
	tree[p].val = max(tree[p << 1].val, tree[p << 1 | 1].val);
}

int query(int p, int l, int r)
{
	if (l <= tree[p].l && tree[p].r <= r)
	{
		return tree[p].val;
	}
	int mid = (tree[p].l + tree[p].r) >> 1;
	if (r <= mid)
	{
		return query(p << 1, l, r);
	}
	else if (l > mid)
	{
		return query(p << 1 | 1, l, r);
	}
	else
	{
		return max(query(p << 1, l, mid), query(p << 1 | 1, mid + 1, r));
	}
}

int main()
{
	int n, d;
	while(~scanf("%d%d", &n, &d))
	{
		int r= -1;
		for (int i = 1; i <= n; ++i)
		{
			scanf("%d", &arr[i]);
			r = max(r, arr[i]);
		}
		build(1, 0, r);
		int ans = 0;
		for (int i = 1; i <= n; ++i)
		{
			if (i - d - 1 > 0)
			{
				update(1, arr[i - d - 1], dp[i - d - 1]);
			}
			if (arr[i] == 0)
			{
				dp[i] = 1;
			}
			else
			{
				dp[i] = query(1, 0, arr[i] - 1) + 1;
			}
			ans = max(ans, dp[i]);
			// printf("%d\n", dp[i]);
		}
		printf("%d\n", ans);
	}
	return 0;
}



  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved