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; }
妈呀来学了下四边形不等式优化= =
首先对于一类2D2D的方程:
$$
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)$的(妈呀我看不懂论文上的证明啊= =)所以方程由$O(n^3)$降为$O(n^2)$
于是这题的$sum$显然满足四边形不等式和区间单调性,所以本题成为水题= =
时间: 2024-10-04 17:37:41