Online JudgeProblem SetAuthorsOnline ContestsUser
Web Board
Home Page
F.A.Qs
Statistical Charts
Problems
Submit Problem
Online Status
Prob.ID:
Register
Update your info
Authors ranklist
Current Contest
Past Contests
Scheduled Contests
Award Contest
User ID:
Password:
  Register

感觉自己斜率优化合格的人进来看看。。求交流。。

Posted by Moon_1st at 2011-08-01 11:27:46 on Problem 3709 and last updated at 2011-08-01 11:30:00
下面是我的一点解题报告,但是对于边界条件——分母为0时,斜率不存在了,不存
在了再用斜率等式还有意义吗?我分情况证明了一下,发现对于这个题依然试用,但
对于其他题目呢,对于存在这种bug的问题呢??详情请看我解题报告”对于边界情
形的一点感想:“那一部分,
下面是我的解题报告:

实际上斜率优化不难,关键是理解了斜率不等式以及单调队列队尾的更新。

此题很容易得到O(n^2)的DP方程:f[i]=Min{f[j]+sum[i]-sum[j]-a[j+1]*(i-j)}。

然后我说一下斜率优化:

假设决策j1<j2并且j2优于(或者不差于)j1,那么

f[j1]+sum[i]-sum[j1]+a[j1+1]*(i-j1) >= f[j2]+sum[i]-sum[j2]-a[j2+1]*(i-j2)    ---------------  不等式(1)

化简得:[(f[j1]-sum[j1]+a[j1+1]*j1) - (f[j2]-sum[j2]+a[j2+1])] >= i*(a[j1+1]-a[j2+1])。

因为有序序列嘛,a[j2+1]>=a[j1+1], 所以a[j1+1]-a[j2+1] <= 0。

所以也可以写成:[(f[j1]-sum[j1]+a[j1+1]*j1) - (f[j2]-sum[j2]+a[j2+1])] / (a[j1+1]-a[j2+1]) <= i。

对于a[j1+1]==a[j2+1]的情况,不能用除法了,只能用乘法那个表达式,

所以,如果对于决策j1,j2满足上述表达式,则j2 优于 j1。

但是如果不满足上述表达式呢,如果不满足那么j2就一定比j1差吗??

NO!!因为如果j1,j2不变,不等式(1)左边是个常数,不会变;而a[j1+1]-a[j2+1] 
<= 0,所以随着i的增加不等式右边是会变小的(或者不变),如果变小的话,那么
有可能在某一个i位置不等式会成立,也就是说在以后较大的某个i,j2会优于j1。

OK,然后我们看看怎样用单调队列结合这两个性质来解这个问题。

令dy(j1, j2) = (f[j1]-sum[j1]+a[j1+1]*j1) - (f[j2]-sum[j2]+a[j2+1]), dx(j1,j2) = 
a[j1+1]-a[j2+1]。

首先刚开始队首元素为0——很明显~~

然后假设队列首尾指针head < tail 并且dy(queue[head],queue[head+1]) >= 
i*dx(queue[head],queue[head+1]),那么队首元素直接丢掉就可以了。因为i是递
增的,如果当前queue[head]没有queue[head+1]好,那么今后也不会。

队尾的操作要稍微难理解一点,不是那么直观:因为对于队尾的2个原素x, y来说,
如果对于当前i,y比x要烂,那么由前面的证明:对于比较大的i,y不一定就比x烂,
有可能比x好呢。那么对这种情况看来不好处理,但是我们来看看队尾3个元素的情
况:x,y,z,如果dy(x,y)/dx(x,y)>=dy(y,z)/dx(y,z),那么可以直接把y给删了。因为
dy(x,y)/dx(x,y)和dy(y,z)/dx(y,z)是个常数,对于某个i,如果dy(x,y)/dx(x,y)<=i的
话,那么dy(y,z)/dx(y,z)一定也小于等于i,也就是说:如果y优于x,那么z一定优于
y,这个时候留着y就没用了。。。。直接删了。。。

对于边界情形的一点感想:实际上上述判断斜率大小的方式在几何角度来说只能针对
x1,x2都不是0或者仅有一个是0的情况,但是对于x1,x2都是0的情况需要对y进行判
断以确定是正无穷还是负无穷(在解析几何方面说实际上是无斜率,但在这个题中却
是有意义的。),有兴趣的可以分情况去讨论一下。dy(x,y)和dy(y,z)有四种极限取
值方式,分别是:(+oo,+oo), (+oo, -oo), (-oo, +oo), (-oo, -oo),其中第1、2、4
种情况可以用代码中的乘法运算比较来判断,但是如果出现第3种情况(这时y优于
x,且y优于z),程序会把y删掉,所以这么判断是错误的。但是这个程序却可以AC
这个题,为什么??因为(-oo, +oo)的情况不会出现 - -,只会出现(-oo, -oo)的情
况;因为如果dx(x,y)==0,那么a[x+1]==a[y+1],那么-sum[x]+a[x+1]*x <= 
-sum[y]+a[y+1]*y,而f[x]<=f[y]恒成立,所以(f[x]-sum[x]+a[x+1]*x) - 
f[y]-sum[y]+a[y+1]*y)是一定小于等于 0的,也就是说如果a[x+1]==a[y+1],则
dy(x,y)一定是小于等于0的,所以对于本题来说是可以这样维护的。(说的有点乱,
有兴趣的同学可以在纸上画画,感觉对于边界的证明想的有点麻犯了;如有更好证明
方法,欢迎提出一起讨论)。

 

好了,主体过程就是这些,需要注意几点:因为有个限制k,所以决策点需要延迟加
入,然后就是数据——记得用long long,最好读得时候也用上,我读的时候用的
int,然后WA了,改成long long就过了,好像按说用int也行,可能是我没处理好。


 

 

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int N = 500010;
typedef long long llg;

int n, k, queue[N];
llg sum[N], f[N], a[N];

llg dy(int j1, int j2)
{
    return  (f[j1]-sum[j1]+a[j1+1]*j1) - (f[j2]-sum[j2]+a[j2+1]*j2);
}

llg dx(int j1, int j2)
{
    return  (a[j1+1] - a[j2+1]);
}

void dp()
{
    int i, j, head, tail, x, y, z;
    head = tail = 0;
    queue[0] = 0;
    for(i = 1; i <= n; i++)
    {
        while(head<tail && dy(queue[head], queue[head+1])>=i*dx(queue[head], queue[head+1]))
            head++;
        j = queue[head];
        f[i] = f[j] + sum[i] - sum[j] - a[j+1]*(i-j);
        if(i >= 2*k-1)    //实际上是i-k+1>=k
        {
            z = i-k+1;
            while(head < tail)
            {
                x = queue[tail-1];
                y = queue[tail];
                if(dy(x,y)*dx(y,z) >= dy(y,z)*dx(x,y))  tail--;
                else  break;
            }
            queue[++tail] = z;
        }
    }
}

int main()
{
    int t, i;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &k);
        sum[0] = 0;
        for(i = 1; i <= n; i++)
        {
            scanf("%I64d", a+i);
            sum[i] = sum[i-1] + a[i];
        }
        dp();
        printf("%I64d\n", f[n]);
    }
    return 0;
}

Followed by:

Post your reply here:
User ID:
Password:
Title:

Content:

Home Page   Go Back  To top


All Rights Reserved 2003-2013 Ying Fuchen,Xu Pengcheng,Xie Di
Any problem, Please Contact Administrator