HAOI2006 數字序列 dp,二分

2022-06-07 02:00:12 字數 1098 閱讀 5043

現在我們有乙個長度為n的整數序列a。但是它太不好看了,於是我們希望把它變成乙個單調嚴格上公升的序列。但是不希望改變過多的數,也不希望改變的幅度太大。求在改變的數最少的情況下,每個數改變的絕對值之和的最小值。

\(n\leq 35000\),保證資料隨機

第一問很容易,只需要令 \(b_i=a_i-i\),然後跑最長不下降子串行即可

下面考慮第二問,令 \(f[i]\) 表示前 \(i\) 個數構成的數列要變成單調上公升需要改動的最小幅度

若 \(a_i,a_j, i滿足 \(a_j-a_i \geq j-i\),則 \([i,j]\) 中一定存在乙個 \(k\),使得 \(a[i\dots k]\) 都變成 \(a[i]\),\(a[k+1\dots j]\) 都變成 \(a[j]\),整個序列上公升並且花費的代價最小,暴力列舉 \(j,k\) 來轉移,時間複雜度為 \(o(n^3)\)

考慮轉移到 \(f[i]\) 的決策點 \(j要求第一問中的 \(g[j]+1=g[i]\),因此轉移點的總數是 \(o(n)\) 到 \(o(n\sqrt n)\) 量級的,且 \(w\) 的區間期望為 \(o(\sqrt n)\),總體複雜度估計為 \(o(n\sqrt n)\) 到 \(o(n^2)\) 之間

在陣列前後額外新增最大最小值,可以提供類似於超級源匯的功能

#include using namespace std;

#define int long long

const int n = 1000005;

int n,a[n],b[n],f[n],g[n],h[n];

vector v[n];

int myabs(int x)

signed main()

++n;

h[1]=b[1]; g[1]=1;

int len=1;

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

else

}for(int i=1;i<=n;i++) v[g[i]].push_back(i);

v[0].push_back(0);

f[0]=0;

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

cout<}

HAOI2006 數字序列

現在我們有乙個長度為n的整數序列a。但是它太不好看了,於是我們希望把它變成乙個單調嚴格上公升的序列。但是不希望改變過多的數,也不希望改變的幅度太大。輸入格式 第一行包含乙個數n,接下來n個整數按順序描述每一項的鍵值。輸出格式 第一行乙個整數表示最少需要改變多少個數。第二行乙個整數,表示在改變的數最少...

HAOI2006 數字序列

現在我們有乙個長度為n的整數序列a。但是它太不好看了,於是我們希望把它變成乙個單調嚴格上公升的序列。但是不希望改變過多的數,也不希望改變的幅度太大。輸入格式 第一行包含乙個數n,接下來n個整數按順序描述每一項的鍵值。輸出格式 第一行乙個整數表示最少需要改變多少個數。第二行乙個整數,表示在改變的數最少...

HAOI2006 數字序列 題解

題目鏈結 現在我們有乙個長度為 n的整數序列 a。但是它太不好看了,於是我們希望把它變成乙個單調嚴格上公升的序列。但是不希望改變過多的數,也不希望改變的幅度太大。第一行是乙個整數,表示序列長度 n。第二行有 n個整數,第 i個整數表示序列的第 i項 ai 第一行輸出乙個整數,表示最少需要改變多少個數...