《算法进阶指南》--一维四边形不等式-诗人小G
对于形如f[i] = min(f[j] + val(j,i)),若函数val()满足四边形不等式,则 f 具有决策单调性。每次计算出f[i],考虑i是(i+1,n)哪些位置的最佳决策。由四边形不等式可以证出:当f[k]+val(k,i)<=f[j]+val(j,i) 且k>j时,f[k]+val(k,i') <= f[j]+val(j,i')。由此可以得出,若f[i]在k位置的解比之前更优,那么(k,n)的解都会更优。这说明对于(i+1,n)存在点k,使得(k+1,n)的位置以i为决策比以小于i为决策更优。可以每次找到这个k点,更新k点及以后的最优解为i。当取出位置 i' 的解时,就是最优决策。每次修改(k,n)可以维护单调队列。当k==n时无需修改队列
int n, l, p;
string poem[N + 10];
int arr[N + 10];
vector<int> prearr;
vector<ld> f;
vector<int> lastindex;
Node dq[N + 10];
int ll = 0, rr = 0;
ld mypow(ld x)
{
ld v = 1;
for (int k = p; k; k >>= 1, x *= x)
if (k & 1)
v *= x;
return (v > 0 ? v : -v);
}
ld fi(int i, int j)
{
return f[j] + mypow(abs(l - (prearr[i] - prearr[j] + i - j - 1)));
}
void solve()
{
cin >> n >> l >> p;
prearr = vector<int>(n + 10);
f = vector<ld>(n + 10);
lastindex = vector<int>(n + 10);
ll = 0, rr = 0;
dq[0] = {1, n, 0};
for (int i = 1; i <= n; i++)
{
cin >> poem[i];
arr[i] = poem[i].size();
prearr[i] = prearr[i - 1] + arr[i];
}
for (int i = 1; i <= n; i++)
{
while (ll <= rr && dq[ll].r < i)
{
ll++;
}
dq[ll].l = i;
int j = dq[ll].j;
f[i] = fi(i, j);
lastindex[i] = j;
int ok = 0;
while (ll <= rr && fi(dq[rr].l, dq[rr].j) >= fi(dq[rr].l, i))
{
ok = 1;
rr--;
}
if (ll <= rr && fi(dq[rr].r, dq[rr].j) >= fi(dq[rr].r, i))
{
ok = 1;
int l = dq[rr].l, r = dq[rr].r, j = dq[rr].j;
int mid;
int jindex;
while (l <= r)
{
mid = (l + r) / 2;
if (fi(mid, j) >= fi(mid, i))
{
r = mid - 1;
}
else
{
jindex = mid;
l = mid + 1;
}
}
dq[rr].r = jindex;
dq[++rr] = {jindex + 1, n, i};
}
else if (ok != 0)
{
int index;
if (ll <= rr)
{
index = dq[rr].r;
}
else
{
i + 1;
}
dq[++rr] = {index + 1, n, i};
}
}
int it = n;
vector<int> end_of_poem;
while (it != 0)
{
end_of_poem.push_back(it);
it = lastindex[it];
}
reverse(end_of_poem.begin(), end_of_poem.end());
it = 0;
if (f[n] <= INF)
{
cout << (int)f[n] << endl;
for (int i = 1; i <= n; i++)
{
cout << poem[i];
if (i != end_of_poem[it])
{
cout << ' ';
}
if (i == end_of_poem[it])
{
it++;
cout << endl;
}
}
}
else
{
cout << "Too hard to arrange" << endl;
}
for (int i = 1; i <= 20; i++)
{
cout << '-';
}
cout << endl;
}
收获:

浙公网安备 33010602011771号