现在的位置: 首页 > 综合 > 正文

POJ 3709 K-Anonymous Sequence 斜率优化

2018年03月17日 ⁄ 综合 ⁄ 共 1084字 ⁄ 字号 评论关闭

容易得出简单的递推方程如下

f[i] = min{f[j] + sum[i] - sum[j] - (i-j) *x[j+1]   }

然后发现复杂度太高

这时可以看出是一个比较经典的斜率优化

f[i] =   min{f[j] +j *x[j+1] -sum[j] -i *x[j+1]}  +sum[i]

按照http://blog.csdn.net/sdj222555/article/details/8229192 中使用的斜率优化方法推导就行了

可以发现一些单调性是比较重要的

最后需要注意的由于有k这个条件的限制

所以某个决策点要入队的时候,需要延迟入队。

就是说走完 i 这个点的时候,把下一个点即(i+1)可能用到的状态加入队列,就是i-k+1

如代码所示

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#define INF 1011111111
#define eps 1e-12
#define MAXN 555555
#define MAXM 55555
using namespace std;
int n, k;
long long f[MAXN], x[MAXN], sum[MAXN];
int q[MAXN];
long long g(int j) {
    return f[j] + (long long)j * x[j] - sum[j];
}
int main() {
    int T;
    scanf("%d", &T);
    while(T--) {
        scanf("%d%d", &n, &k);
        for(int i = 0; i < n; i++) x[i] = in();
        sum[0] = 0;
        for(int i = 1; i <= n; i++) sum[i] = sum[i - 1] + x[i - 1];
        int l = 1, r = 1;
        q[1] = 0; f[0] = 0;
        for(int i = 1; i <= n; i++) {
            while(q[l] + 2 * k <= i) l++;
            while(l < r && (long long)i * (x[q[l + 1]] - x[q[l]]) >= g(q[l + 1]) - g(q[l])) l++;
            f[i] = f[q[l]] + x[q[l]] * (long long)(q[l] - i) + sum[i] - sum[q[l]];
            if(i - k + 1 >= k) {
                while(l < r && (g(q[r]) - g(q[r - 1])) * (x[i - k + 1] - x[q[r]]) >= ((g(i - k + 1) - g(q[r])) * (x[q[r]] - x[q[r - 1]]))) r--;
                q[++r] = i - k + 1;
            }
        }
        printf("%I64d\n", f[n]);
    }
    return 0;
}

抱歉!评论已关闭.