hdu45221――小明系列問題――小明序列 線段樹優化dp
來源:程序員人生 發布時間:2014-12-07 10:04:41 閱讀次數:3430次
小明系列問題――小明序列
Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 1918 Accepted Submission(s): 583
Problem Description
大家都知道小明最喜歡研究跟序列有關的問題了,可是也就由于這樣,小明幾近已玩遍各種序列問題了。可憐的小明苦苦地在各大網站上尋覓著新的序列問題,可是找來找去都是自己早已研究過的序列。小明想既然找不到,那就自己來發明1個新的序列問題吧!小明想啊想,終究想出了1個新的序列問題,他欣喜若狂,由于是自己想出來的,因而將其新序列問題命名為“小明序列”。
提起小明序列,他給出的定義是這樣的:
①首先定義S為1個有序序列,S={ A1 , A2 , A3 , ... , An },n為元素個數 ;
②然后定義Sub為S中取出的1個子序列,Sub={ Ai1 , Ai2 , Ai3 , ... , Aim },m為元素個數 ;
③其中Sub滿足 Ai1 < Ai2 < Ai3 < ... < Aij⑴ < Aij < Aij+1 < ... < Aim ;
④同時Sub滿足對任意相連的兩個Aij⑴與Aij都有 ij - ij⑴ > d (1 < j <= m, d為給定的整數);
⑤明顯滿足這樣的Sub子序列會有許許多多,而在取出的這些子序列Sub中,元素個數最多的稱為“小明序列”(即m最大的1個Sub子序列)。
例如:序列S={2,1,3,4} ,其中d=1;
可得“小明序列”的m=2。即Sub={2,3}或{2,4}或{1,4}都是“小明序列”。
當小明發明了“小明序列”那1刻,情緒非常激動,以致于頭腦混亂,因而他想請你來幫他算算在給定的S序列和整數d的情況下,“小明序列”中的元素需要多少個呢?
Input
輸入數據多組,處理到文件結束;
輸入的第1行動兩個正整數 n 和 d;(1<=n<=10^5 , 0<=d<=10^5)
輸入的第2行動n個整數A1 , A2 , A3 , ... , An,表示S序列的n個元素。(0<=Ai<=10^5)
Output
請對每組數據輸出“小明序列”中的元素需要多少個,每組測試數據輸出1行。
Sample Input
2 0
1 2
5 1
3 4 5 1 2
5 2
3 4 5 1 2
Sample Output
Source
2013騰訊編程馬拉松初賽第4場(3月24日)
Recommend
liuyiding | We have carefully selected several similar problems for you: 5137 5136 5135 5134 5133
Statistic | Submit | Discuss
| Note
這道題唯1的看點就在n的范圍很大以致于暴力會超時
狀態方程很好想,dp[i] = max(dp[j] + 1)其中a[i] > a[j]
我們把以第i個元素為結尾的最長上升子序列放到線段樹對應值為a[i]的葉子上(有點hash思想,這是為了保證上升這個特性,查詢的時候方便),固然如果此時的i-d<=1就不用插入了,這時候候用不到任何的前置狀態。
需要用我們就插入1次,而且每次插入我們都能保證那個點和當前點i的距離1定大于d(之前已空了d個位置),到時就直接去線段樹上小于a[i]的區間找最大值就好了
#include <map>
#include <set>
#include <list>
#include <queue>
#include <stack>
#include <vector>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
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= ⑴;
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
", dp[i]);
}
printf("%d
", ans);
}
return 0;
}
生活不易,碼農辛苦
如果您覺得本網站對您的學習有所幫助,可以手機掃描二維碼進行捐贈