zoukankan      html  css  js  c++  java
  • HDU 3507 Print Article

    传送门

    题目大意:

    将给定序列分段输出,输出每段的费用计算式已经给出,就最小的输出费用。

    题目分析:

    首先列出转移方程:

    [f[i] = max{f[j] + (sum[i] - sum[j]) ^ 2 + M} ]

    转移是(n^2)的,下面考虑优化。

    如果j比l优,即(f[j] + (sum[i] - sum[j]) ^ 2 + M <= fl] + (sum[i] - sum[l]) ^ 2 + M),化简得:

    [S(j, l) = frac{(f[j] + sum[j]^2) - (f[l] + sum[l]^2)}{2(sum[j] - sum[l])} le sum[i] ]

    观察到上式,可以使用斜率优化。

    一篇很好的博客

    用斜率维护下凸包,更新答案即可。注意斜率优化时尽量使用乘法代替除法,避免精度问题。

    code

    #include<bits/stdc++.h>
    using namespace std;
    const int N = 500050, M = 1050;
    int n, m, c[N];
    int que[N];
    int head, tail;
    int f[N], sum[N];
    
    inline int calc(int i, int j){
    	return f[j] + (sum[i] - sum[j]) * (sum[i] - sum[j]) + m;
    }
    
    inline bool slopeCheck(int i, int j, int k){
    	return ((f[i] + sum[i] * sum[i]) - (f[j] + sum[j] * sum[j])) * 2 * (sum[j] - sum[k]) <=
    		   ((f[j] + sum[j] * sum[j]) - (f[k] + sum[k] * sum[k])) * 2 * (sum[i] - sum[j]);
    }
    
    int main(){
    	freopen("h.in", "r", stdin);
    	while(scanf("%d%d", &n, &m)!=EOF){
    		memset(f, 0, sizeof f);
    		sum[0] = 0;
    		for(int i = 1; i <= n; i++) scanf("%d", &c[i]), sum[i] = sum[i - 1] + c[i];
    		que[head = tail = 1] = 0;
    		for(int i = 1; i <= n; i++){
    			while(head + 1 <= tail && calc(i, que[head]) >= calc(i, que[head + 1])) head++;
    			f[i] = calc(i, que[head]);
    			while(head <= tail - 1 && slopeCheck(i, que[tail], que[tail - 1])) tail--;
    			que[++tail] = i;
    		}
    		printf("%d
    ", f[n]);
    	}
    	return 0;
    } 
    
  • 相关阅读:
    easyExcel入门
    UML-从需求到设计--迭代进化
    UML-操作契约总结
    102. Binary Tree Level Order Traversal
    98. Validate Binary Search Tree
    95. Unique Binary Search Trees II
    96. Unique Binary Search Trees
    94. Binary Tree Inorder Traversal
    84. Largest Rectangle in Histogram
    92. Reverse Linked List II
  • 原文地址:https://www.cnblogs.com/CzYoL/p/7744941.html
Copyright © 2011-2022 走看看