• [SDOI2008]Sue的小球


    XXIX.[SDOI2008]Sue的小球

    DP做多了,手感自然就出来了。

    话说这题打着“小球”的名字题目中却是“彩蛋”是怎么回事

    首先,这个下落速度\(v\),尽管题面中说它可能为负数,但我们想一想,这可能吗?如果是负数答案就是正无穷(可以等着这个球一直向上飞),因此排除球速为负的可能。

    如果是这样的话,那么,当我们经过一个球时,随手将它射爆明显是更好的行为。因此,无论何时,我们球已经被射下的位置一定是一个包含起始点\(x_0\)的区间。

    我们将所有球按照位置在\(x_0\)左边还是右边压进两个vector中(下标从\(0\)开始)。在左边的vector(设为\(v1\))中,我们按照\(x\)值从大到小排序并处理;在右边(设为\(v2\)),我们从小到大排序。同时,我们在\(v1\)\(v2\)中都压入一个\(x=x_0\)的球,方便初始化。

    我们设\(f[i][j][0/1]\)表示:当前进行到\(v1\)的第\(i\)位,\(v2\)的第\(j\)位,同时位于这个区间的左/右端点的情况。我们可以提前计算出所有小球初始\(y\)值的和,这样我们只需要最小化捡球过程中球下落的距离即可。

    我们设\(s[i][j]\)表示:除了\(v1\)\(i\)位和\(v2\)\(j\)位外,其它球\(1s\)内下落的距离之和(这借鉴了XII.任务安排费用提前计算的经典思想)。在实现中,这个可以直接通过前缀和做出。设\(x1[i]\)表示\(v1\)\(x\)值,\(x2[j]\)表示\(v2\)\(x\)值。

    我们有

    \(f[i][j][0]=f[i-1][j][0]+\Big|x1[i-1]-x1[i]\Big|*(s[i-1][j])\)

    \(f[i][j][1]=f[i][j-1][0]+\Big|x2[j-1]-x2[j]\Big|*(s[i][j-1])\)

    然后因为两边可以互相走,所以还有

    \(f[i][j][0]=f[i][j][1]+\Big|x2[j]-x1[i]\Big|*s[i][j]\)

    \(f[i][j][1]=f[i][j][0]+\Big|x1[i]-x2[j]\Big|*s[i][j]\)

    两种转移取\(\min\)即可。

    复杂度\(O(n^2)\)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    int n,X,s1[1010],s2[1010],sy,f[1010][1010][2],sv;
    struct node{
    	int x,y,v;
    	node(int a=0,int b=0,int c=0){x=a,y=b,v=c;}
    }b[1010];
    vector<node>v1,v2;
    bool cmp1(const node &x,const node &y){
    	return x.x<y.x;
    }
    bool cmp2(const node &x,const node &y){
    	return x.x>y.x;
    }
    int main(){
    	scanf("%d%d",&n,&X),memset(f,0x3f3f3f3f,sizeof(f));
    	for(int i=1;i<=n;i++)scanf("%d",&b[i].x);
    	for(int i=1;i<=n;i++)scanf("%d",&b[i].y),sy+=b[i].y;
    	for(int i=1;i<=n;i++)scanf("%d",&b[i].v);
    	for(int i=1;i<=n;i++){
    		if(b[i].x<X)v1.push_back(b[i]);
    		if(b[i].x>X)v2.push_back(b[i]);
    	}
    	v1.push_back(node(X,0,0)),v2.push_back(node(X,0,0));
    	sort(v1.begin(),v1.end(),cmp2);
    	sort(v2.begin(),v2.end(),cmp1);
    	for(int i=1;i<v1.size();i++)s1[i]=s1[i-1]+v1[i].v;
    	for(int i=1;i<v2.size();i++)s2[i]=s2[i-1]+v2[i].v;
    //	for(int i=0;i<v1.size();i++)printf("%d %d %d\n",v1[i].x,v1[i].y,v1[i].v);puts("");
    //	for(int i=0;i<v2.size();i++)printf("%d %d %d\n",v2[i].x,v2[i].y,v2[i].v);puts("");
    	sv=s1[v1.size()-1]+s2[v2.size()-1];
    	f[0][0][0]=f[0][0][1]=0;
    	for(int i=0;i<v1.size();i++)for(int j=0;j<v2.size();j++){
    		if(i)f[i][j][0]=f[i-1][j][0]+abs(v1[i].x-v1[i-1].x)*(sv-s1[i-1]-s2[j]);
    		if(j)f[i][j][1]=f[i][j-1][1]+abs(v2[j].x-v2[j-1].x)*(sv-s1[i]-s2[j-1]);
    		f[i][j][0]=min(f[i][j][0],f[i][j][1]+abs(v2[j].x-v1[i].x)*(sv-s1[i]-s2[j]));
    		f[i][j][1]=min(f[i][j][1],f[i][j][0]+abs(v1[i].x-v2[j].x)*(sv-s1[i]-s2[j]));
    	}
    	double res=sy-min(f[v1.size()-1][v2.size()-1][0],f[v1.size()-1][v2.size()-1][1]);
    	res/=1000;
    	printf("%.3lf\n",res);
    	return 0;
    }
    

  • 相关阅读:
    [书籍精读]《JavaScript异步编程》精读笔记分享
    [技术翻译]在现代JavaScript中编写异步任务
    [技术翻译]Web网页内容是如何影响电池使用寿命的?
    [技术翻译]使用Nuxt生成静态网站
    [Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串
    [Vue源码]一起来学Vue双向绑定原理-数据劫持和发布订阅
    [Vue源码]一起来学Vue模板编译原理(一)-Template生成AST
    [技术翻译]您应该知道的13个有用的JavaScript数组技巧
    css清除默认样式
    [小技巧]让你的GridView支持IQueryable,并自动实现真分页
  • 原文地址:https://www.cnblogs.com/Troverld/p/14597068.html
Copyright © 2020-2023  润新知