現在我們有乙個長度為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 第一行輸出乙個整數,表示最少需要改變多少個數...