zoukankan      html  css  js  c++  java
  • HDU 2829 Lawrence

    有点复杂的斜率优化题。

    前置知识:

    i=1nj=i+1naiaj=(i=1nai)2i=1nai22        (1)sum_{i=1}^n sum_{j=i+1}^n a_i*a_j=dfrac{(sum_{i=1}^n a_i)^2- sum_{i=1}^n a_i^2}{2}~~~~~~~~ (1)
    证明:
    方法1:
    ab=(a+b)2a2b22ab=dfrac{(a+b)^2-a^2-b^2}{2}
    ab+ac+bc=(a+b+c)2a2b2c22ab+ac+bc=dfrac{(a+b+c)^2-a^2-b^2-c^2}{2}
    ……………………
    方法2:
    (1)式等价于i=1nj=1naiaj=(i=1ai)(i=1ai)sum_{i=1}^n sum_{j=1}^n a_i*a_j =(sum_{i=1}a_i)*(sum_{i=1}a_i)
    很明显,这是正确的。因为aiaja_i*a_j就相当于从左边括号取一个数乘上右边括号的一个数。

    思路:

    题目要求的是把n个数分成连续的m+1段的最小费用,每一段的费用等于段内每个数两两相乘的和。
    f[i][j]ija[i]isa设f[i][j]表示把前i个数分成j段的最小费用,a[i]为第i个数,s为a的前缀和,ss[i]=j=1ia[i]2ss[i]=sum_{j=1}^i a[i]^2
    则有:f[i][j]=min   f[k][j1]+(s[i]s[k])2(ss[i]ss[k])2f[i][j]=min~~~f[k][j-1]+dfrac{(s[i]-s[k])^2-(ss[i]-ss[k])}{2}
             f[i][j]=f[k][j1]+2s[i]s[k]+s[i]2ss[i]+s[k]2+ss[k]2~~~~~~~~~f[i][j]=f[k][j-1]+dfrac{-2s[i]*s[k]+s[i]^2-ss[i]+s[k]^2+ss[k]}{2}
    化成            y                      =   k     x   +          b                      ~~~~~~~~~~~~y~~~~~~~~~~~~~~~~~~~~~~=~~~k~~~~~x~~~+~~~~~~~~~~b~~~~~~~~~~~~~~~~~~~~~~的形式
    f[k][j1]+ss[k]+s[k]22=s[i]s[k]+f[i][j]s[i]2ss[i]2f[k][j-1]+dfrac{ss[k]+s[k]^2}{2}=s[i]*s[k]+f[i][j]-dfrac{s[i]^2-ss[i]}{2}
    斜率、横坐标单调递增,就可做了。
    代码:

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    typedef long long ll;
    const int N=1010;
    int n,m,q[N],l,r,u,v;
    ll f[N][2],s[N],ss[N];
    ll x(int i){return s[i];}
    double y(int i){return f[i][v]+0.5*(s[i]*s[i]+ss[i]);}
    bool pd(int i,int j,int k)
    {
    	return (y(j)-y(i))*(x(k)-x(j))<(y(k)-y(j))*(x(j)-x(i));
    }
    #define g getchar()
    template<class o>
    void qr(o&x)
    {
    	char c=g;x=0;
    	while(!('0'<=c&&c<='9'))c=g;
    	while('0'<=c&&c<='9')x=x*10+c-'0',c=g;
    }
    int main()
    {
    	while(1)
    	{
    		qr(n);qr(m);
    		if(!n&&!m)return 0;m++;
    		for(int i=1;i<=n;i++)
    			qr(s[i]),ss[i]=s[i]*s[i]+ss[i-1],s[i]=s[i]+s[i-1];
    		for(int i=1;i<=n;i++)
    			f[i][0]=(s[i]*s[i]-ss[i])>>1;
    		u=1;v=0;
    		for(int j=2;j<=m;j++,swap(u,v))
    		{
    			l=r=1;q[l]=j-1;
    			for(int i=j,k;i<=n;i++)
    			{
    				while(l<r&&y(q[l+1])-y(q[l])<=s[i]*(x(q[l+1])-x(q[l])))l++;
    				k=q[l];
    				f[i][u]=f[k][v]+((1LL*(s[i]-s[k])*(s[i]-s[k])-ss[i]+ss[k])>>1);
    				while(l<r&&!pd(q[r-1],q[r],i))r--;
    				q[++r]=i;
    			}
    		}
    		printf("%lld
    ",f[n][v]);
    	}
    }
    
  • 相关阅读:
    其他:Oracle并购sun之后的影响之我见
    60款很酷的 jQuery 幻灯片演示和下载
    分享35个高质量的 Apple 风格图标素材
    25个漂亮的旅游网站设计作品欣赏
    tomcat内存溢出总结
    一个非常强大完整的web表单验证程序
    java socket (回顾)
    jdbc 公共类(2)
    各大IT公司笔试真题汇总
    软件公司的岗位职责
  • 原文地址:https://www.cnblogs.com/zsyzlzy/p/12373909.html
Copyright © 2011-2022 走看看