zoukankan      html  css  js  c++  java
  • bzoj 1010 [HNOI2008] 玩具装箱toy (斜率优化第一题)

    题意:中文题,大意就不说了,但这个Sigma的确让我看了好久

    思路:看了网上的很多题解,大概对斜率优化有了一点了解,发现斜率优化这种东西用在很多方面,比如在对凸壳的求解中,常用的kuangbin凸包模板中就有斜率优化的例子,对于单调队列的认识是基于某次被学弟们踩的一次训练(bzoj 1012 [JSOI2008] 最大数maxnumber,这个题用点掉队列的解法的确很巧妙,orz.),而斜率优化,与点掉队列优化类似,队列优化解决的是在dp方程中,经过一些变化后,可以将dp方程两侧化为dp[i]和dp[j],而无dp[i]*dp[j]类似的项,就是不牵扯高次幂项,而写斜率优化正是将相乘的两项转化为一种特殊的函数,转变成在二维平面上的一些点,在决策性的讨论上,根据所变形得到的方程,来决定维护上凸壳还是下凸壳。

    首先附上超时代码O(n2);

    加个字符读入板子:

    inline char nc() {
        static char ibuf[RLEN],*ib,*ob;
        (ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
        return (ib==ob) ? -1 : *ib++;
    }
    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=50005;
    const int INF=0x3f3f3f3f;
    typedef long long LL;
    LL pre[maxn],dp[maxn];
    int a[maxn];
    int n,l;
    
    int main()
    {
        scanf("%d%d",&n,&l);
        pre[0]=0;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            pre[i]=pre[i-1]+a[i];
        }
        memset(dp,0x3f,sizeof(dp));
        dp[0]=0;
        for(int i=1;i<=n;i++){
            int j;
            int as;
            for(j=0;j<i;j++){
                as=i-j-1+pre[i]-pre[j]-l;
                dp[i]=min(dp[i],dp[j]+as*as);
            }
        }
        printf("%lld
    ",dp[n]);
        return 0;
    }

    然后抄袭hzw大牛的代码:

    #include <bits/stdc++.h>
    const int inf=1000000000;
    typedef long long ll;
    using namespace std;
    ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
        return x*f;
    }
    int n,L,l,r;
    int c[50005],q[50005];
    ll s[50005],f[50005],C;
    double slop(int j,int k)
    {
        return (f[k]-f[j]+(s[k]+C)*(s[k]+C)-(s[j]+C)*(s[j]+C))/(2.0*(s[k]-s[j]));
    }
    int main()
    {
        n=read();L=read();C=L+1;
        for(int i=1;i<=n;i++)c[i]=read();
        for(int i=1;i<=n;i++)s[i]=s[i-1]+c[i];
        for(int i=1;i<=n;i++)s[i]+=i;//这里是因为在dp方程中吧前缀和与i进行合并了
        l=1;r=0;q[++r]=0;
        for(int i=1;i<=n;i++){
            while(l<r&&slop(q[l],q[l+1])<=s[i])l++;
            int t=q[l];//取出队首
            f[i]=f[t]+(s[i]-s[t]-C)*(s[i]-s[t]-C);//这里其实是dp方程
            while(l<r&&slop(q[r],i)<slop(q[r-1],q[r]))r--;//由斜率方程可以得出,维护的是下凸壳,所以当队列存在且
            q[++r]=i;                   //加入决策i时,令队尾为q[r],前一个为q[r-1]
                                //满足斜率(q[r],i)<斜率(q[r-1],q[r])时,显然队尾是无效的,将其弹出
        }
        printf("%lld
    ",f[n]);
        return 0;
    }
  • 相关阅读:
    [ActionSprit 3.0] FMS直播
    Selenium学习之==>Css Selector使用方法
    Selenium学习之==>Xpath使用方法
    Selenium学习之==>WebDriver驱动对照表
    Selenium学习之==>Selenium介绍
    HTML学习之==>JS
    HTML学习之==>DOM操作
    HTML学习之==>CSS
    HTML学习之==>HTML标签
    Python学习之==>线程&&进程
  • 原文地址:https://www.cnblogs.com/lalalatianlalu/p/8477472.html
Copyright © 2011-2022 走看看