BZOJ 1229: [USACO2008 Nov]toy 玩具

35 篇文章 0 订阅
16 篇文章 1 订阅

题意:就是经典餐巾问题 就是天数特别大 到了10^5

这道题弄了我好久啊,第一道三分题,不过好像三分并不难,我怕我讲不好,网上那么多我就不在这里说了。

网上面题解写的简直是太草率+简单了吧。坑爹的百度连中国网都搜不到 这里有一篇还不错的点击打开链接

弄得我还丧心病狂的看一下别人韩国人的题解。(强行用谷歌翻译看。。有兴趣的童鞋自己去吧点击打开链接

对了 这道题的网络流版本其实挺不错的 模型要掌握啊。网络流:http://blog.csdn.net/cgh_andy/article/details/51931420


我希望我能尽量讲好这道题,因为题解少,我缺证明实在太烦,其实题目不难,可是就是要一个证明,相信也会有人跟我一样执着,也希望我能帮助到后面的人。

我们来讲一下弄了最久的:证明单峰性!(这是用三分做之前需要做的)

我们设一个函数 f(玩具数)=费用  g(玩具数)=分配费用  ∴f(x)=g(x)+tc*x

对于g(x)我们可以发现 玩具数越多 g(x)越小 所以这是一个递减函数且 g(x)-g(x-1)<=g(x+1)-g(x) 

上面这个好好想(我不保证我说的清,所以我也不好解释,但是这的确是个好方向)

我们便可以发现 f(x)-f(x-1)=g(x)-g(x-1)+tc  ->  f(x)-f(x-1)<=f(x+1)-f(x)

然后斜率就递增然后就单峰啦啦啦啦啦


这里给两个比较平滑的说法:

1、对于费用流,在最优解的情况下,买多一条毛巾,意味着走多一条最短路,费用增加。少买一条,那么等于少走一条某个时刻的最短路,走了第二短路什么的,费用也是增加,故单峰。

2、对于分配费用,在最优情况下,买多一条肯定浪费,买少了就需要更多的钱去洗,所以单峰。。。


官方题解关于g数组:(反正我英语不好 用什么翻译都看不懂)

g is clearly a decreasing function of t, since having more toys can't possibly hurt. To be convex means that the improvement in g from adding each new toy is no greater than the improvement from the last toy added. This is intuitively clear, since if we add a toy, then anything we could've done with this toy to cut down costs could also have been done with the last toy. This can be made rigorous. Adding a toy just means that, at certain points, we can choose the cheaper option to clean a toy. If adding a second toy gives us a bigger savings than the first toy, we could've just chosen the cheaper option at all the points we chose for the second toy, except instead when we added the first toy. So, adding a later toy can never help us more than adding an earlier toy. This shows that g is convex, so the algorithm we proposed works, and we are done.

Note: To be even more explicit, on day i suppose that we use ai toys cleaned with the cheap method and bi toys cleaned with the expensive method. Let ai1, ai2, ai3 denote the ai for t, t+1, and t+2 toys. It is necessary and sufficient to show that sum( ai3-ai2 ) <= sum( ai2 - ai1 ).

Indeed, if (a11,...,ak1) is a possible sequence of ai values for t toys, and similarly for (a12, ...) and (a13, ...), then (a11-a12+a13, ...) is easily seen to be a possible sequence for t+1 toys, so it follows that sum( ai1-ai2+ai3-ai1) = sum( ai3-ai2 ) <= sum( ai2-ai1), since the ai2 are an optimal sequence of ai values for t+1 toys. This is a more algebraic proof of the argument we just made.

最后给出代码:

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define inf 1000000000
#define me(a,x) memset(a,x,sizeof a)
#define cp(a,x) memcpy(a,x,sizeof a)
using namespace std;
struct node{int x,y;}d[100010],s[100010],q[100010];
int a[100010],n,n1,n2,c1,c2,tc;
int f(int x)
{
    int i,ret=(tc-c2)*x,l,r,sl,sr,ql,qr;
    l=sl=ql=r=1,sr=qr=0;
    d[1].x=-inf,d[1].y=x;
    for(i=1;i<=n;i++)
    {
        while(l<=r && i-d[l].x>=n1) q[++qr]=d[l++];
        while(ql<=qr && i-q[ql].x>=n2) s[++sr]=q[ql++];
        int p=a[i];
        while(p)
        {
            if(sl<=sr)
            {
                if(s[sr].y>p)
                    s[sr].y-=p, ret+=p*c2 , p=0;
                else
                    p-=s[sr].y, ret+=s[sr--].y*c2;
            }
            else if(ql<=qr)
            {
                if(q[qr].y>p)
                    q[qr].y-=p, ret+=p*c1 , p=0;
                else
                    p-=q[qr].y, ret+=q[qr--].y*c1;
            }
            else return inf;
        }
        d[++r].x=i,d[r].y=a[i];
    }
    return ret;
}
int main()
{
    scanf("%d%d%d%d%d%d",&n,&n1,&n2,&c1,&c2,&tc);
    if(n1>n2) swap(n1,n2),swap(c1,c2);
    if(c1<c2) c2=c1;
    int i,l=1,r=0;
    for(i=1;i<=n;i++)scanf("%d",&a[i]),r+=a[i];
    while(1)
    {
        if(r-l<=5)
        {
            int t=f(l);
            for(i=l+1;i<=r;i++)t=min(t,f(i));
            printf("%d\n",t);
            break;
        }
        int x=l+(r-l)/3,y=l+2*(r-l)/3;
        int fx=f(x),fy=f(y);
        if(fx!=inf && fx<=fy)r=y;
        else l=x;
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值