现在证明 $w_{i,j}$ 满足四边形不等式,设 $a\leq b\leq c\leq d$,$w_{a,c}+w_{b,d}-w_{a,d}-w_{b,c}=(\sqrt{c-a}+\sqrt{d-b})-(\sqrt{d-a}+\sqrt{c-b})$,学习过导数的同学都知道 $\operatorname{f}(x)=x^{\frac{1}{2}}$ 的导函数是 $\operatorname{f'}(x)=\frac{x^{-\frac{1}{2}}}{2}$,导函数单调递减,因此上述值始终不小于 $0$,可以判断出 $w_{x,y}$ 满足四边形不等式。
::::info[参考代码]
```cpp
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int, int> PII;
const int N = 5e5 + 10;
int n, p [ N ];
ld h [ N ], f [ N ], g [ N ];
double w ( int j, int i ) {
if ( j == 0 ) return -1e18;
return h [ j ] + sqrt ( i - j ) - h [ i ];
}
void sol ( int pl, int pr ) {
if ( pr == pl + 1 ) {
if ( w ( pr, pr ) > f [ pr ] )
f [ pr ] = w ( pr, pr ), p [ pr ] = pr;
return;
}
int mid = pl + pr >> 1;
p [ mid ] = p [ pl ], f [ mid ] = w ( p [ mid ], mid );
for ( int i = p [ pl ] + 1; i <= p [ pr ]; ++i )
if ( w ( i, mid ) > f [ mid ] ) f [ mid ] = w ( i, mid ), p [ mid ] = i;
sol ( pl, mid );
for ( int i = pl + 1; i <= mid; ++i )
if ( w ( i, pr ) > f [ pr ] ) f [ pr ] = w ( i, pr ), p [ pr ] = i;
sol ( mid, pr );
}
signed main ( ) {
cin >> n;
for ( int i = 1; i <= n; ++i ) cin >> h [ i ];
for ( int i = 1; i <= n; ++i ) p [ i ] = i;
p [ 0 ] = 0; sol ( 0, n );
for ( int i = 1; i <= n; ++i ) g [ i ] = f [ i ];
for ( int i = 1; i <= n; ++i ) f [ i ] = 0, p [ i ] = i;
p [ 0 ] = 0; reverse ( h + 1, h + 1 + n ); sol ( 0, n );
for ( int i = 1; i <= n; ++i ) g [ i ] = max ( g [ i ], f [ n - i + 1 ] );
for ( int i = 1; i <= n; ++i ) {
ll ans = ( ll ) ceil ( g [ i ] - 1e-10 );
if ( ans < 0 ) ans = 0;
cout << ans << '\n';
}
return 0;
}
```
::::
---
[CF321E Ciel and Gondolas](https://codeforces.com/contest/321/problem/E)
设 $\operatorname{w}(x,y)$ 为矩阵左上角为 $(x,x)$,右下角为 $(y,y)$ 的和。
因此对于 $a\leq b\leq c\leq d$,$\operatorname{w}(a,c)+\operatorname{w}(b,d)\leq\operatorname{w}(a,d)+\operatorname{w}(b,c)$。
画图更容易验证,因为后者比前者覆盖的面积更大,且前者是完全被后者所覆盖。
状态转移方程显然是 $f_{i,j}=f_{i-1,k-1}+\operatorname{w}(k,j)$。
::::info[参考代码]
```cpp
#include <bits/stdc++.h>
using namespace std;
namespace IO {
const int BUF_SIZE = 1 << 20;
char inbuf[BUF_SIZE], outbuf[BUF_SIZE];
char *p1 = inbuf, *p2 = inbuf;
int outpos = 0;
inline char getchar() {
if (p1 == p2) {
p1 = inbuf;
p2 = inbuf + fread(inbuf, 1, BUF_SIZE, stdin);
if (p1 == p2) return EOF;
}return *p1++;
}
template <typename T> inline T read() {
T x = 0, f = 1;
char ch = getchar();
while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
while (ch >= '0' && ch <= '9') { x = (x << 1) + (x << 3) + (ch - '0'); ch = getchar(); }
return x * f;
}
template <typename T> inline void write(T x, char en = '\n') {
if (outpos >= BUF_SIZE - 32) { fwrite(outbuf, 1, outpos, stdout); outpos = 0;}
if (x < 0) { outbuf[outpos++] = '-'; x = -x; }
char temp[64]; int len = 0;
do { temp[len++] = x % 10 + '0'; x /= 10; } while (x);
while (len--) outbuf[outpos++] = temp[len];
outbuf[outpos++] = en;
}
inline void flush() {if (outpos) fwrite(outbuf, 1, outpos, stdout); outpos = 0;}
}using namespace IO;
const int N = 4010, K = 810;
int n, k, x, sum [ N ][ N ];
int f [ K ][ N ], p [ K ][ N ];
int w ( int u, int v ) {
return sum [ v ][ v ] - sum [ v ][ u - 1 ] - sum [ u - 1 ][ v ] + sum [ u - 1 ][ u - 1 ];
}
void sol ( int s, int pl, int pr ) {
if ( pr == pl + 1 ) {
if ( w ( pl + 1, pr ) + f [ s - 1 ][ pl ] < f [ s ][ pr ] )
f [ s ][ pr ] = w ( pl + 1, pr ) + f [ s - 1 ][ pl ], p [ s ][ pr ] = pl + 1;
return;
}
int mid = pl + pr >> 1;
p [ s ][ mid ] = p [ s ][ pl ], f [ s ][ mid ] = f [ s - 1 ][ p [ s ][ mid ] - 1 ] + w ( p [ s ][ mid ], mid );
for ( int i = p [ s ][ pl ] + 1; i <= p [ s ][ pr ]; ++i )
if ( w ( i, mid ) + f [ s - 1 ][ i - 1 ] < f [ s ][ mid ] )
f [ s ][ mid ] = w ( i, mid ) + f [ s - 1 ][ i - 1 ], p [ s ][ mid ] = i;
sol ( s, pl, mid );
for ( int i = pl + 1; i <= mid; ++i )
if ( w ( i, pr ) + f [ s - 1 ][ i - 1 ] < f [ s ][ pr ] )
f [ s ][ pr ] = w ( i, pr ) + f [ s - 1 ][ i - 1 ], p [ s ][ pr ] = i;
sol ( s, mid, pr );
}
signed main ( ) {
n = read < int > ( ), k = read < int > ( );
for ( int i = 1; i <= n; ++i ) {
for ( int j = 1; j <= n; ++j ) {
sum [ i ][ j ] = sum [ i - 1 ][ j ] + sum [ i ][ j - 1 ] - sum [ i - 1 ][ j - 1 ] + read < int > ( );
}
}
for ( int i = 1; i <= n; ++i ) f [ 0 ][ i ] = 1e9;
f [ 0 ][ 0 ] = 0;
for ( int i = 1; i <= k; ++i ) {
for ( int j = 1; j <= n; ++j ) f [ i ][ j ] = 1e9;
p [ i ][ 1 ] = 1, p [ i ][ n ] = n;
sol ( i, 0, n );
}
write ( f [ k ][ n ] >> 1 ), flush ( );
return 0;
}
```
::::
---
::::info[参考资料]
- [参考资料1](https://www.luogu.com.cn/article/vqf42hah)
- [参考资料2](https://oi-wiki.org/dp/opt/quadrangle/)
::::