zoukankan      html  css  js  c++  java
  • 题解 P3628 【[APIO2010]特别行动队】

    题目链接:Link

    Problem

    Solution

    不难写出方程:

    [f(i)=minlimits_{0 le j < i } { f(j)+a(s_i-s_j)^2+b(s_i-s_j)+c } ]

    去掉min函数,展开得:

    [f(i)=f(j)+a*s_i^2 - a*s_i*s_j + a*s_j^2 + b*s_i - b*s_j + c ]

    将仅与j有关的项、乘积项、和其余的分开,得:

    [f(j)+a*s_j^2-b*s_j=2*a*s_i*s_j + f(i) - a*s_i^2 - b* s_i - c ]

    则在这个线性规划模型中,对于每个决策i,决策点位于 $ ( s_i , f(i) + a * s_i^2 - b * s_i ) $ 。
    对于每个要求的 $ f(i) $ ,直线斜率为 $ 2 * a * s_i * s_j $ ,截距为 $ f(i) - a * s_i^2 - b * s_i - c $ 。
    整个过程中有如下性质:

    • $ s_j $ 单调增
    • 直线斜率单调减

    故可用单调队列维护这个斜率优化过程。

    Code

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long LL;
    const int maxn=1000005;
    int n,Q[maxn],L,R;
    LL a,b,c,v[maxn],s[maxn],X[maxn],Y[maxn],f[maxn];
    int main()
    {
    	#ifdef local
    	freopen("pro.in","r",stdin);
    	#endif
    	scanf("%d%lld%lld%lld",&n,&a,&b,&c);
    	for(int i=1;i<=n;i++) scanf("%lld",&v[i]);
    	for(int i=1;i<=n;i++) s[i]=s[i-1]+v[i];
    	Q[L=R=1]=0;
    	for(int i=1;i<=n;i++)
    	{
    		while(L<R&&(Y[Q[L+1]]-Y[Q[L]])>=2*a*s[i]*(X[Q[L+1]]-X[Q[L]])) L++;
    		int j=Q[L];
    		f[i]=f[j]+a*(s[i]-s[j])*(s[i]-s[j])+b*(s[i]-s[j])+c;
    		X[i]=s[i]; Y[i]=f[i]+a*s[i]*s[i]-b*s[i];
    		while(L<R&&(Y[Q[R]]-Y[Q[R-1]])*(X[i]-X[Q[R-1]])<=(Y[i]-Y[Q[R-1]])*(X[Q[R]]-X[Q[R-1]])) R--;
    		Q[++R]=i;
    	}
    	printf("%lld
    ",f[n]);
    	return 0;
    }
    
  • 相关阅读:
    Lazarus教程 中文版后续给出
    QBASIC教程
    Object Pascal中文手册 经典教程
    Pascal 基础教程
    Delphi中的关键字与保留字
    Pascal数据结构与算法
    Pascal小游戏 贪吃蛇
    Pascal小游戏 俄罗斯方块怀旧版
    Pascal ASCII和文本的转换
    IDEA安装问题解决
  • 原文地址:https://www.cnblogs.com/happyZYM/p/11629602.html
Copyright © 2011-2022 走看看