http://acm.hdu.edu.cn/showproblem.php?pid=3506
题意:环形石子合并取最小值= =(n<=1000)
#include <cstdio>
#include <algorithm>
using namespace std;
const int N=2005, oo=~0u>>1;
int a[N], w[N], d[N][N], s[N][N], n;
int main() {
while(~scanf("%d", &n)) {
for(int i=1; i<=n; ++i) scanf("%d", &a[i]), a[i+n]=a[i];
n=2*n;
int ans=oo;
for(int i=1; i<=n; ++i) w[i]=w[i-1]+a[i];
for(int i=1; i<n; ++i) d[i][i+1]=a[i]+a[i+1], s[i][i+1]=i+1;
for(int len=3; len<=n; ++len) {
for(int i=1; i<=n-len+1; ++i) {
int j=i+len-1, l=s[i][j-1], r=s[i+1][j], &now=d[i][j], &pos=s[i][j];
now=oo;
for(int k=l; k<=r; ++k) {
if(now>=d[i][k-1]+d[k][j]) {
now=d[i][k-1]+d[k][j];
pos=k;
}
}
now+=w[j]-w[i-1];
}
}
for(int i=1; i<=(n>>1); ++i) ans=min(ans, d[i][i+(n>>1)-1]);
printf("%d\n", ans);
}
return 0;
}
妈呀来学了下四边形不等式优化= =
首先对于一类2D1D的方程:
$$
d(i, j)=
\begin{cases}
min \{ d(i, k-1)+d(k, j) \}+w(i, j) & i<j \\
0 & i=j \\
oo & i>j
\end{cases}
$$
(取$max$的我还没分析过,不过我们能将$w(i, j)=-w(i, j)$然后将$max$取$min$就好啦hhh(咦这应该没问题吧?))
我们有下边的定理(证明可以去看论文或者q我= =)
如果$i \le i' \le j \le j'$就有$w(i, j)+w(i', j') \le w(i', j)+w(i, j')$(四边形不等式)
且如果$i \le i' \le j' \le j$就有$w(i', j') \le w(i, j)$(区间单调性)
设$s(i, j)=max \{ k|d(i, j)=d(i, k-1)+d(k, j)+w(i, j) \}$那么有:
$$
\begin{align}
d(i, j)+d(i', j') & \le d(i', j)+d(i, j') \\
s(i, j) \le s(i, j+1) & \le s(i+1, j+1)
\end{align}
$$
而$s$的取值每一个确定的$l=j-i+1$是$O(n)$的(妈呀我看不懂论文上的证明啊= =,这样搞:(s[2,L+1]-s[1,L])+(s[3,L+2]-s[2,L+1])…+(s[n-L+1,n]-s[n-L,n-1])=s[n-L+1,n]-s[1,L]≤n)所以方程由$O(n^3)$降为$O(n^2)$
于是这题的$sum$显然满足四边形不等式和区间单调性,所以本题成为水题= =