這道題真的很好,寫題解的人寫的也真好
如果要保留 a[i],a[i] 和 a[j],a[j] ,
前提是:他們中間的數本身就合法,或者他們中間的數可以被改成合法。
比如,17,50,50,50,19這個序列,看上去17和19能保留,但如果保留,中間三個50怎麼改都不會單調上公升。
可見只有 a[j],a[j] 和 a[i],a[i] 的差大於等於j-i才允許同時保留兩者,否則中間一定出錯。
a[j] - a[i] >= j - i移項:
a[j] - j >= a[i] - i此為保留條件。
所以把根據 a 預處理出新序列 b[i] = a[i] - i,
然後找 b的最長不下降子串行的長度,就是最多能保留的個數。
把 a變成嚴格單調上公升序列等同於:在 b 上對應地處理,並把 b 變成單調不降。
現在就考慮 b怎麼改才能代價最小。
注意:(一) b 的最長不下降子串行可能有多個。
(二) b 的最長不下降子串行中,任何兩個相鄰的元素 b[i], b[j]
(相鄰指的是在子串行中相鄰,而在 b 中不一定相鄰) 之間
,絕對不存在另乙個大小介於兩者之間的元素。
否則取這個元素,保證合法,而且可以使不降序列更長。
所以每個被保留的 b[i]和 b[j] 之間的元素全部不合法。怎麼改變這兩者之間的元素?
黑線表示修改以後的海拔。顯然所有方法都是階梯(橫線看作台階)。此方法看上去很糟。
如果台階上的「上公升點數目」大於「下降點數目」,那麼把台階下降(以滿足那麼多「上公升點」的要求!),
直到它下降到和左邊台階一樣高,也就和左邊變成了同一塊台階。
反之,就把台階上公升到和右邊台階一樣高。然後繼續縮減台階。
如果有up = down的,則台階向上向下都可以(代價不變,台階數目減少)。
這個過程始終保證合法、保證代價減小或不變。
這樣變化到end,一定只剩下兩塊台階,左邊的高 b[i],右邊的高 b[j] 。
以上說明,最優解一定是(或者說,一定可以是)
左邊 b[i] to b[k] 全部變成 b[i] 且
右邊 b[k+1] to b[j] 全部變成 b[j]
的形態。
如果最優解不是這樣,我們可以無償甚至減償來變成這種形態。
每個區間的 k可以列舉。
code by std
#include #include #include inline int getint()
#define re register
#define ll long long
#define inf 2147483647
inline ll min(ll x, ll y)
inline ll abs(ll x)
int n;
int a[40010], b[40010];
int minof[40010], len = 0, longest[40010];
int first[40010], to[40010], nxt[40010], cnt = 0;
ll f[40010];
ll suml[40010], sumr[40010];
inline void adde(int u, int v)
int main()
if(l == len)
++len;
longest[i] = l+1;
adde(longest[i], i);
minof[l+1] = b[i];
}adde(0, 0);
printf("%d\n", n-(len-1));
memset(f, 20, sizeof(f));
b[0] = -inf;f[0] = 0;
for(re int i = 1; i <= n+1; ++i)
}printf("%lld\n", f[n+1]);
return 0;
}
C 之奇技淫巧
typedef struct data 0 pdata 0 typedef struct data 1 pdata 1 結構體data 0與data 1在性質上沒有什麼不同,它們的size是相等的,都是8.但在用法上有很大區別。例 pdata 0 stack0 pdata 0 malloc max ...
git 奇技淫巧
例如 1.0.0 git tag a 1.0.0 m 1.0.0 版本的備註資訊.複製 git push origin tags 複製 例如 1.0.0 git tag d 1.0.0 複製 刪除遠端標籤需要先刪除本地標籤,再執行下面的命令 git push origin refs tags 1.0...
c 的奇技淫巧
關於陣列 數論演算法技巧 stl其他 while scanf d d n,m eof 等價於 while scanf d d n,m 2 前者eof為檔案結束符,較保險 後者 後的數字為輸入的變數的個數 不能只寫while scanf d d n,m 這樣無法結束讀入 wwq大佬教的,希望我不要和他...