zoukankan      html  css  js  c++  java
  • 【洛谷 P3648】 [APIO2014]序列分割 (斜率优化)

    题目链接
    假设有(3)(a,b,c)
    先切(ab)和先切(bc)的价值分别为
    (a(b+c)+bc=ab+bc+ac)
    ((a+b)c+ab=ab+bc+ac)
    归纳一下可以发现切的顺序并不影响总价值。
    于是设(f[i][j])表示前(i)个数切(j)次的最大价值,转移方程就很简单了。
    然后斜率优化一下就能降时间复杂度降到(O(nk))
    (f[i][j]=f[k][j-1]+sum[k]*(sum[i]-sum[k]))
    (f[k][j-1]-sum[k]^2=-sum[i]*sum[k]+f[i][j])
    水分神器斜率优化

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    const int MAXN = 100010;
    const int MAXM = 205; 
    #define ll long long
    #define re register
    
    int n, m, p;
    int q[MAXN], head, tail, sum[MAXN], fa[MAXN][MAXM];
    ll f[MAXN][MAXM];
    
    inline double k(int t, int i, int j){
    	if(sum[i] == sum[j]) return -2e18;
    	return (double)(f[i][t] - f[j][t] - (ll)sum[i] * sum[i] + (ll)sum[j] * sum[j]) / (sum[i] - sum[j]);
    }
    int main(){
    	scanf("%d%d", &n, &m);
    	for(re int i = 1; i <= n; ++i){
    	   scanf("%d", &p);
    	   sum[i] = sum[i - 1] + p;
        }
    	for(re int j = 1; j <= m; ++j){
    	   head = tail = 0;
    	   for(re int i = 1; i <= n; ++i){
    	      while(head < tail && k(j - 1, q[head], q[head + 1]) > -sum[i]) ++head;
    	      re int l = q[head];
    	      f[i][j] = f[l][j - 1] + (ll)sum[l] * (sum[i] - sum[l]);
    	      fa[i][j] = l;
    	      while(head < tail && k(j - 1, q[tail - 1], q[tail]) <= k(j - 1, q[tail], i)) --tail;
    	      q[++tail] = i;
    	   }
        }
        printf("%lld
    ", f[n][m]);
        int now = fa[n][m];
        while(m--){
        	printf("%d ", now);
        	now = fa[now][m];
        }
        return 0;
    }
    
  • 相关阅读:
    博客最新博文通告
    博文快速导航
    创业
    央行回应中国版数字货币:与人民币等价 不会让钱贬值
    高屋建瓴
    高层人对事的处理
    老板的区别
    沟通的四大法则
    赚钱规则
    合伙做生意的原则
  • 原文地址:https://www.cnblogs.com/Qihoo360/p/10329012.html
Copyright © 2011-2022 走看看