HDU 2836 離散化DP 區間優化

2022-07-04 12:36:15 字數 1551 閱讀 3256

題目鏈結

題目大意:計算序列有多少種組合,每個組合至少兩個數,使得組合中相鄰兩個數之差不超過h,序列有重複的數。mod 9901。

解題思路

以樣例1 3 7 5為例,如果沒有重複的數。

設dp[i]前n個數的方案數,初始化為1。

那麼for(1...i...n)

$dp[i]=\sum dp[j]+1\quad,where \quad \left |num[i]-num[j] \right|<=h$

+1是為了計算兩個點直接連線的情況,如樣例:

dp[1]=1 (無連線)

dp[2]=dp[1]+1=2 (1-3連線)

dp[3]=1 (無連線)

dp[4]=dp[2]+dp[3]+1=4(1-3-5, 3-5,7-5)

如果沒有+1,那麼就沒法dp下去,同時,這樣每個點多算了1,所以ans=1+2+1+4-4=4

上面o(n^2)的原因在於, 原始序列的dp區間不是連續的,比如1,3,8,3,5,7 h=2

5的dp區間可以是2,4,需要多掃一輪來找出這些離散的值。

實際上,dp過程中可以不依賴原始序列順序。將原始序列排序離散化去重後,變成1,3,5,8

這樣,新新增乙個box的時候,可以二分找其值在新序列中邊界l,r,這樣,原本的離散dp求和,

被轉化成了連續區間求和$\sum sum(r)-sum(l-1)$

原因很簡單,5在實際計算時,在3,3,7中都被牽扯到,是乙個對稱計算。所以排序去重後可以簡化為對連續區間的計算。

至於為什麼要去重,主要是為了解決重值的重複計算(原題並沒有說沒有重值)

比如1,3,3,如果不去重,為第二個3單獨開個dp狀態,那麼1-3被算了兩次(dp初始值為1)

所以第二個3,無須再開乙個dp狀態,直接第乙個3基礎上算就行了。保證ans-n是最後的結果。

#include "

cstdio

"#include

"algorithm

"#include

"cstring

"using

namespace

std;

#define maxn 100005

#define mod 9901

intnum[maxn],hash[maxn],n,h,s[maxn];

int lowbit(int x)

int sum(int

x)void update(int x,int

d)int

main()

sort(hash+1,hash+n+1

);

int diff=unique(hash+1,hash+n+1)-hash-1

;

int ans=0

;

for(int i=1;i<=n;i++)

printf(

"%d\n

",(ans-n)%mod);

}}

hdu 5009 離散化 鍊錶 dp

這道題因為顏色給的資料範圍大於資料總數,所以要對顏色進行離散化後再進行操作 而這道題每次更新,可以用鍊錶記錄當前情況下每種顏色最靠近當前位置的所在位置後,因為最終花費是c c,所以每乙個所選區間的顏色數不能大於sqrt 區間長度 所以可以得到n sqrt n 複雜度演算法的動態規劃如下 dp i m...

HDU 3607 線段樹 離散化 DP

n個連續的盒子,每個盒子有高度h和價值v,選擇任意一點進入,且從任意一點出來,進入後只能從左向右走,且每次走到的盒子高度必須更高,可以跳過低的盒子 狀態轉移方程 dp i max dp j v i 0 jh j 用線段樹優化,尋找 j include stdio.h include string.h...

hdu5542 樹狀陣列 離散化 dp

推薦 通過離散化 樹狀陣列 優化 include using namespace std const int mod 1e9 7 const int maxn 1e3 60 int s maxn 最初的陣列 int e maxn 排序後的書序 int num maxn 儲存 離散化後的位置 int ...