BestCoder Round #4

27 篇文章 0 订阅
14 篇文章 0 订阅

HDUOJ 4931 Happy Three Friends

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4931

给出6个数,A可以调整顺序,B先选出首尾两个数,C再从剩下的四个数当中选出3个数,问B选出的两个数之和有没有可能比C选出的3个数之和大。

因为A是帮B的,所以,B如果是聪明人的话,他肯定是从这6个数当中挑出最大的两个数,C也足够聪明,他会从剩下的四个数当中挑3个比较大的数。

那么问题就简单了,现将数据排序,然后比较a[4]+a[5]>a[1]+a[2]+a[3]即可。

亏我一开始想的是枚举全排列。。。。

下面是AC代码:

#include<iostream>
#include<algorithm>
using namespace std;
int n,m,ans[15],flag;
int a[15];//待排列的数存储在此
int main()
{
    int t;
    cin>>t;
    while(t--)
    {
        for(int i=0;i<6;i++) cin>>a[i];
        sort(a,a+6);
        if(a[1]+a[2]+a[3]<a[4]+a[5]) cout<<"Grandpa Shawn is the Winner!"<<endl;
        else cout<<"What a sad story!"<<endl;
        //dfs(0,0);
    }
    return 0;
}
HDUOJ 4932 Miaomiao's Geometry

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4932

这道题,就是说给出n个数,然后构造一些长度一致的区间,这些区间重叠部分不能大于0,而且这n个数最后都要在某些区间的端点上。求区间长度最大值。

由于以前在《挑战程序设计竞赛》这本书上看过《二分法,不光是求解值!!!》这一章,我第一思路就是想二分长度,然后,对于每个长度以线性的时间计算出是否可行,这种问题一般就是用贪心,仔细思考之后,便可以很容易想出如何用线性的复杂度判断某个区间长度是否可行,贪心思想是这样的,对于每个点,尽量构造区间使得这个点成为构造出区间的右端点,为什么这样是正确的呢?可想而知,这样做比让这个点成为左端点更优优势。自己画画图就明白了。

然后二分枚举区间长度就行了。

代码如下

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=105,inf=1<<29;
int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};
int n,m,t,a[maxn];
bool judge(double x)
{
    double prel=a[0]*1.0;
    for(int i=1;i<n;i++)
    {
        if(a[i]*1.0<prel) return 0;
        if(a[i]-x>=prel) prel=a[i]*1.0;
        else prel=a[i]*1.0+x;
    }
    return 1;
}
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0;i<n;i++) cin>>a[i];
        sort(a,a+n);
        double l=0.0,r=1e10;
        for(int i=0;i<100;i++)
        {
            double mid=(l+r)/2;
            if(judge(mid)) l=mid;
            else r=mid;
        }
        printf("%.3lf\n",l);
    }
    return 0;
}

不过,这个代码提交上去,华丽丽地WA了,思考之下,终于想出了原因, 二分的时候,答案必需要满足单调性啊,这里小的数据不行,大的数据可以行!如 0 1 5 6 10, 3不行,4行。

再细想之,其实区间长度只可能是相邻两个点距离之差,或者这个差的一半,为什么一半也行呢?还是0 1 5 6 10这组数据,比如6和10之间,长度为2也可满足,因为可以构造区间[6,8],[8,10]。

那么有好解决了,答案只可能是2*(n-1)种情况下,n=50,也只不过98中,枚举之,每种判断是否可行依然可用上述贪心思想。

然后是AC了,下面是AC代码:

#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#include<sstream>
#include<fstream>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<set>
#include<queue>
#define LL long long
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1 | 1
using namespace std;
const int maxn=105,inf=1<<29;
int dir[][2]={ {0,1},{-1,0},{0,-1},{1,0},{-1,1},{-1,-1},{1,-1},{1,1}};
int n,m,t,a[maxn];
bool judge(int x)
{
    int prel=a[0];//perl存的是已经构造好了的区间的右端点
    for(int i=1;i<n;i++)
    {
        if(a[i]<prel) return 0;//如果当前点已经被上一次的区间包含,则这种区间长度是失败的
        if(a[i]-x>=prel) prel=a[i];//更新区间右端点
        else if(a[i]+x!=a[i+1]) prel=a[i]+x;//如果当前点和下一点不能刚好构造成一个区间则更新右端点
    }
    return 1;
}
int main()
{
    cin>>t;
    while(t--)
    {
        cin>>n;
        for(int i=0;i<n;i++) cin>>a[i],a[i]*=2;//乘是为了后面能整除,避免用double型带来不必要的误差
        sort(a,a+n);
        int ans=1;
        for(int i=1;i<n;i++)
        {
            int L=a[i]-a[i-1];
            if(judge(L)) ans=max(ans,L);//差
            if(judge(L/2)) ans=max(ans,L/2);//差的一半
        }
        printf("%.3lf\n",ans*1.0/2);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值