Usaco 生气的奶牛 - (dp&滑窗)|(二分&贪心check)

来源:互联网 发布:淘宝首页装修教程视频 编辑:程序博客网 时间:2024/06/10 02:13

生气的奶牛
题目描述
在数轴x上摆放有n(2<=n<=50000)捆干草堆,没有任何两堆在同样的位置,所有的位置均为整数。你可以用弹弓射击射击数轴上的任意地点。如果你用弹弓以R的力度射击x处,那么该处会发生爆炸,爆炸的范围是以R为半径的圆形区域,所以它会使得[x-R,x+R]的所有干草堆同时发生爆炸。这些干草堆的爆炸半径是R-1。它们又会触发连锁反应,第三轮的爆炸的半径为R-2,依次递减。请选择最小的力度射击,使得所有的干草堆全部爆炸。

输入
第一行包含N。接下来N个整数,表示干草堆的位置。所有位置在[0,1000000000]内。

输出
输出最小的力度R,使得所有的干草堆发生爆炸。四舍五入保留一位小数。

样例输入
5
8 10 3 11 1

样例输出
3.0

提示
样例解释:
如果以力度3射击坐标5,则坐标3,坐标8处的干草堆会发生爆炸,然后又会引爆坐标1和坐标10的干草堆,最后引爆坐标11处的干草堆。

来源
usaco gold 2016.1

Solution 1:dp+滑窗

分析:

dp[][0]是一个单调不递减的数列,dp[][1]是一个单调不上升的数列。
就dp[][0]举例:
当距离(a[i]-a[x])较大,dp[x][0]+1较小的时候,由于求两者的较大值,很显然可以调小距离,相应的调大dp[x][0]+1,因此将x往右移。
如果没有这样的更优的x,就只有用max(dp[i-1][0],a[i]-a[i-1])了。

#include<cstdio>#include<algorithm>#include<cstring>using namespace std;#define INF 2000000000#define MAXN 50000int n,a[MAXN+10],dp[MAXN+10][2];void Read(int &x){    char c;    while(c=getchar(),c!=EOF){        if(c>='0'&&c<='9'){            x=c-'0';            while(c=getchar(),c>='0'&&c<='9')                x=x*10+c-'0';            ungetc(c,stdin);            return ;        }    }}void read(){    Read(n);    for(int i=1;i<=n;i++)        Read(a[i]);    sort(a+1,a+n+1);}void DP() //分别dp出把干草堆左面和后面的爆炸完要的最小R{    memset(dp,0,sizeof dp);    for(int i=2,x=1;i<=n;i++){        while(x<i&&a[i]-a[x]>dp[x][0])            x++;        if(x!=i)            dp[i][0]=dp[x][0]+1;        else            dp[i][0]=max(dp[i-1][0],a[i]-a[i-1]);    }    for(int i=n-1,x=n;i>=1;i--){        while(x>i&&a[x]-a[i]>dp[x][1])            x--;        if(x!=i)            dp[i][1]=dp[x][1]+1;        else            dp[i][1]=max(dp[i+1][1],a[i+1]-a[i]);    }}void workout(){    int i=1,j=n;    double ans=INF*1.0;    while(i<j){        ans=min(ans,max((a[j]-a[i])/2.0,min(dp[i][0],dp[j][1])+1.0));        if(dp[i+1][0]<dp[j-1][1])            i++;        else            j--;    }    printf("%.1lf\n",ans);}int main(){    read();    DP();    workout();    return 0;}

二分+贪心check(From Liu Junhao)

这是他的blog链接

粘一个他的代码,珍藏一下

#include<cstdio>#include<cstring>#include<algorithm>using namespace std;#define MAXN 50000int n,a[MAXN+10],d[MAXN+10];void Read(int &x){    char c;    while(c=getchar(),c!=EOF)        if(c>='0'&&c<='9'){            x=c-'0';            while(c=getchar(),c>='0'&&c<='9')                x=x*10+c-'0';            ungetc(c,stdin);            return;        }}void read(){    Read(n);    for(int i=1;i<=n;i++)        Read(a[i]);    sort(a+1,a+n+1);}bool check(double R){    double mxr,mir;    d[1]=0;    int i,j;    for(i=1;i<=n;){        if(i==n)            return 1;        for(j=i+1;a[j]-a[i]<=d[i]+1&&j<=n;j++);        if(j>i+1)            j--;        if(a[j]-a[i]>R-1){            mxr=a[i]+R;            break;        }        d[j]=max(d[i]+1,a[j]-a[i]);        i=j;        if(d[i]>R-2&&d[i]<=R-1){            mxr=a[i]+R;            break;        }    }    d[n]=0;    for(i=n;i;){        if(i==1)            return 1;        for(j=i-1;a[i]-a[j]<=d[i]+1&&j;j--);        if(j<i-1)            j++;        if(a[i]-a[j]>R-1){            mir=a[i]-R;            break;        }        d[j]=max(d[i]+1,a[i]-a[j]);        i=j;        if(d[i]>R-2&&d[i]<=R-1){            mir=a[i]-R;            break;        }    }    if(mxr>=mir)        return 1;    return 0;}double partition(double l,double r){    double mid;    int i=0;    while(++i<=70){        mid=(l+r)/2;        if(check(mid))            r=mid;        else            l=mid;    }    return l;}int main(){    read();    printf("%.1lf\n",partition(1,1000000000));}
0 0
原创粉丝点击