Baidu Astar Contest 2013-03-23 Regional (Wuhan)

  • 2013年3月23号竞赛题目一

    主办方: 百度公司
    开始时间:2013-03-23 20:00
    结束时间:2013-03-23 22:00
    已结束

     

    平衡负载

    Du熊正在负责一个大型的项目,目前有K台服务器,有N个任务需要用这K台服务器来完成,所以要把这些任务分成K个部分来完成,在同上台服务器上执行的任务必须是连续的任务,每个任务有各自需要的执行时间。

    例如N=5,K=2,每个任务需要时间分别为5,3,1,4,7分钟,那么我们可以分成(5)(3 1 4 7)两部分,这样第一台服务器所花时间就是5分钟,而第二台机器需要花15分钟,当然,所有任务完成的时间是按最迟完成的那台服务器的时间,即这样划分的话完成所有任务所需要的时间就是15分钟。而另外一种划分方法是(5 3 1)(4 7),这种划分方案完成所有任务的时间就是11分钟,也是最优的一种划分方案。

    现在你的任务就是根据给定的N,K和每个任务要花费的时间,找出使完成所有任务时间最短的方案。

     

    输入:

    多组输入。

    第一行输入N和K(1<=K<=N<=10000)。

    第二行输入N个不大于1000的正整数,表示各个任要花费的时间。

    N=K=0表示输入结束。

     

    输出:

    每行输出一个整数,对应对于每个数据(除了N=K=0不用输出)。

     

    样例输入:

     

    5 1
    5 3 1 4 7
    5 2
    5 3 1 4 7
    5 3
    5 3 1 4 7
    10 3
    1 2 3 4 5 6 7 8 9 10
    0 0

     

    样例输出:

     

    20
    11
    8
    21

#include <cstdio>

int main() {
        int n, k, t[10000];
        while (scanf("%d%d", &n, &k) != EOF && !(n == 0 && k == 0)) {
                int tsum = 0, tmax = 0;
                for (int i = 0; i < n; ++i) {
                        scanf("%d", &t[i]);
                        tsum += t[i];
                        tmax = tmax > t[i] ? tmax : t[i];
                }
                int high = tsum, low = tmax, ans = -1;
                while (low <= high) {
                        int mid = (low + high) >> 1;
                        int cur = 0, cnt = 1;
                        int i = 0;
                        while (i < n) {
                                cur += t[i];
                                if (cur > mid) {
                                        ++cnt;
                                        cur = t[i];
                                }
                                if (cnt > k) break;
                                ++i;
                        }
                        if (i < n)
                                low = mid + 1;
                        else // i == n
                                ans = mid, high = mid - 1;
                }
                printf("%d\n", ans);
        }
        return 0;
}


二分一下答案,然后贪心分段,再判断一下分出来的段数是否小于k就可以了。

#include <cassert>
#include <valarray>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <fstream>
#include <numeric>
#include <iomanip>
#include <bitset>
#include <list>
#include <stdexcept>
#include <functional>
#include <utility>
#include <ctime>
#include <complex>
#include <memory>
using namespace std;
// begin insertdefines
#define forE(elem,v)  for(__typeof__(v.begin())_it = v.begin(); _it != v.end();++_it) for(int_once=1, _done=0; _once; (!_done) ? (_it=v.end(), --_it) :_it ) for(__typeof__(*_it)& elem = * _it; _once && !(_once=0); _done=1)
typedef vector<int> VRI;
// end insertdefines
bool check(const VRI &a, const int K, const int m)
{
    int sNum = 0, acc = 0;
    forE(ai, a) {
        if (ai> m) return false;
        acc += ai;
        if (acc> m) {
            acc = ai;
            sNum++;
        }
    }
    sNum++;
    return sNum <= K;
}
int main(int argc, char *argv[])
{
    int N, K;
    while (true) {
        scanf("%d%d",&N, &K);
        if (!N&& !K) break;
        assert(1 <= N && N <=10000);
        assert(1 <= K && K <= N);
        VRI a(N);
        forE(ai, a) scanf("%d",&ai);
        forE(ai, a) assert(1 <= ai&& ai <= 1000);
        int l = 0,r = 0;
        forE(ai, a) r += ai;
        while (l <r) {
            int m = (l+ r) / 2;
            if(check(a, K, m))
                r = m;
            else l = m +1;
        }
        printf("%d\n", l);
    }
    return 0;
}



  • 2013年3月23号竞赛题目二

    主办方: 百度公司
    开始时间:2013-03-23 20:00
    结束时间:2013-03-23 22:00
    已结束

     

    水果忍者

    题目描述

     

        你知道水果忍者吗?这是一个智能手机上面很流行的游戏。

        这个出色的游戏迎合了人类最喜爱的运动轨迹:抛物线。就是各种各样物体被扔出去之后都会形成的曲线运动。现在这里的问题也是关于抛物线的。

        现在有N个水果,假设它们就是一个个在平面上的的圆,有着同样的半径。每个水果有着各自的位置和移动速度。由于重力的影响(这里假设重力常数g=10),所有水果都从一开始就沿着抛物线运动。你的目标就是在给定的时间限制之内,一次切到最多的水果,即是找到在某一时刻的一条直线穿过最多的圆。

     

     

    输入格式

     

    输入包含多给测试数据。

    输入的第一行给出了测试数据个数T。

     

    每个测试数据首先给出三个整数,水果数目N(<=100),水果的半径R(<=1000),还有时间限制E(<=1000)。

    接下来有N行,每行给出4个实数,分别对应圆心坐标(xi, yi)和速度(vxi,vyi)。

    所有数都是采用标准单位,所以你可以放心使用以下著名的物理公式来计算某一时刻水果所处的位置:

    x' = x + vx * t

    y' = y + vy * t - 0.5 * 10 * t * t

    数据保证所有的浮点数的绝对值小于100000。

     

    输出格式

    对应每个测试数据,输出一个整数,即在时限内可以同时切到的水果数目的最大值。

     

    样例输入

     

    2
    4 1 2
    2.0 4.0 1.0 0.0
    5.0 4.0 2.0 0.0
    2.0 12.0 1.5 -4.0
    -2.0 -5.0 10.0 10.0
    4 1 1
    2.0 4.0 1.0 0.0
    5.0 4.0 2.0 0.0
    2.0 12.0 1.5 -4.0
    -2.0 -5.0 10.0 10.0

     

    样例输出

     

    4
    3

     

    提示

    请注意一条直线“穿过”一个圆意味着,圆心与直线的距离小于圆的半径加上精度误差(1e-5)。


可以知道肯定存在这样的最优解:切出来的直线肯定和某两个圆相切,否则我们可以旋转和移动直线使得它满足这个条件。
于是我们可以枚举这两个圆,然后枚举切线,求出所有的其它圆被切线超过的时间区间,最后做一下最大区间覆盖就可以求出在哪一个时刻这条切线切过最多水果。解方程可以用牛顿法来解。
其实可以证明一个更强的结论,就是一定存在一个最优解和某两个圆外相切。

#include <cstdio>
#include <cstring>
#include <cmath>
#include <cassert>
#include <algorithm>
#include <vector>
using namespace std;
const int maxn = 101;
const double INF = 1e8;
const double EPS = 1e-5;
const double MAXLOOP = 100;
struct seg {
    seg() { l = 1; r = 0; }
    seg(double il, double ir) { l = il; r = ir; }
    bool empty() { return r < l - EPS; }
    double l, r;
};
struct point {
    int mrk;
    double pos;
}points[maxn * 2];
struct vect {
   
    double d[20];
    int n;
    int size() {
        return n;
    }
    vect() {
        n= 0;
    }
    void push_back(double x) {
        d[n++] = x;
    }
    double operator [] (int index) {
        return d[index];
    }
};
int pn;
double x[maxn], y[maxn], vx[maxn],vy[maxn];
int n, r, e; // number, radius, time limit
int best; // maximum number of cutting
void add_seg(seg &s) {
    if (abs(s.l - s.r)<EPS) s.r = s.l;
    points[pn].mrk = 1;
    points[pn].pos = s.l;
    ++pn;
    points[pn].mrk = 0;
    points[pn].pos = s.r;
    ++pn;
}
vectdifferentiate(vect co) {
    vect res;
    for (int i = 1; i < co.size(); ++i) {
        res.push_back(co * i);
    }
    return res;
}
double substitute(vect co, double x) {
    double res = 0, tmp = 1;
    for (int i = 0; i < co.size(); ++i) {
        res += tmp * co;
        tmp *= x;
    }
    return res;
}
vectremove_dup(vect vec) {
    vect res;
    if (vec.size() == 0) return res;
    //sort(vec.begin(), vec.end());
    sort(vec.d, vec.d+vec.n);
    res.push_back(vec[0]);
    for (int i=1;i<vec.size();++i) {
        if (vec - vec[i-1] > EPS * 10)res.push_back(vec);
    }
    return res;
}
bool newton(vect co, vect dco, double x, double &res_x) {
    double last = -INF;
    int count = 0;
    while (count++ < MAXLOOP) {
        double f = substitute(co, x);
        double fp = substitute(dco, x);
        if ( abs(fp) < EPS ) {
            // no idea whether this works
            x += EPS;
            continue;
        }
        x -= f / fp;
        if ( abs(x - last) < EPS ) {
            res_x = x;
            return true;
        }
        last = x;
    }
    return false;
}
vectsolveeqs(vect co) {
    vect root;
   
    if (co.size() <= 2) {
        if (co.size() == 2 && co[1] != 0) {
            root.push_back(-co[0] / co[1]);
        }
        return root;
    }
    vect dco = differentiate(co); // differentail coefficient
    vect droot = solveeqs(dco);
    droot.push_back(-INF);
    droot.push_back(INF);
    sort(droot.d, droot.d+droot.n);
    //sort(droot.begin(), droot.end());
   
    for (int i=1;i<droot.size(); ++i) {
        double initx = (droot[i-1] + droot)* 0.5, res;
        if (newton(co, dco, initx, res)) {
            root.push_back(res);
        }
    }
    return remove_dup(root);
}
//sigma(ax^n) <= 0
vector<seg> solvele(vect co) {
    vect root = solveeqs(co);
    vector<seg> res;
    bool neg = substitute(co, -INF) < 0 ;
    double last = -INF;
    for (int i=0;i<root.size();++i) {
        if (neg) {
            res.push_back(seg(last, root));
        }
        last = root;
        neg ^=1;
    }
    if (neg) res.push_back(seg(last, INF));
    return res;
}
vectnegpoly(vect co) {
    for (int i = 0; i < co.size(); ++i) {
        //co *= -1;
        co.d *= -1;
    }
    return co;
}
vector<seg> solvege(vect co) {
    return solvele(negpoly(co));
}
vectmultipoly(vect co1, vect co2) {
    vect res;
    for (int i = 0; i<co1.size()+co2.size()-1;++i) res.push_back(0);
    for (int i = 0; i < co1.size(); ++i) {
        for (int j = 0; j < co2.size(); ++j) {
            //res[i+j] += co1 * co2[j];
            res.d[i+j] += co1 * co2[j];
        }
    }
    return res;
}
vectsumpoly(vect co1, vect co2) {
    vect res;
    for (int i = 0; i < co1.size() || i < co2.size(); ++i) {
        double ta, tb;
        if (i < co1.size()) ta = co1; else ta = 0;
        if (i < co2.size()) tb = co2; else tb = 0;
        res.push_back(ta + tb);
    }
    return res;
}
// ax +b
vect lco(double a, double b) {
    vect res;
    res.push_back(b);
    res.push_back(a);
    return res;
}
segintersect(seg a, seg b) {
    seg res;
    if (a.l > b.l) res.l = a.l; else res.l = b.l;
    if (a.r < b.r) res.r = a.r; else res.r = b.r;
    return res;
}
void fix_time_limit(seg &ret) {
    if (ret.l < 0) ret.l = 0;
    if (ret.r > e) ret.r = e;
}
void calc_valid_seg( int a, int b, int c) {
    double x1 = x[b] - x[a], x2 = x[c] - x[a];
    double y1 = y[b] - y[a], y2 = y[c] - y[a];
    double vx1 = vx[b] - vx[a], vx2 = vx[c] - vx[a];
    double vy1 = vy[b] - vy[a], vy2 = vy[c] - vy[a];
    vect tmp;   
    vect co = sumpoly(multipoly(lco(vy1, y1), lco(vx2, x2)),negpoly(multipoly(lco(vy2, y2), lco(vx1, x1))));
    //  int start2 =clock();
    vector<seg> seg1 = solvege(co);
    tmp.push_back(-4*r*r);
    vect co2 = sumpoly(multipoly(co, co),multipoly(sumpoly(multipoly(lco(vx1,x1), lco(vx1,x1)), multipoly(lco(vx1,x1),lco(vx1,x1))), tmp));
    vector<seg> seg2 = solvele(co2);
    for (int i = 0; i < seg1.size(); ++i) {
        fix_time_limit(seg1);
        if (seg1.empty()) continue;
        for (int j = 0; j < seg2.size(); ++j){
            fix_time_limit(seg2[j]);
            if (seg2[j].empty()) continue;
            seg tmpseg = intersect(seg1,seg2[j]);
            if (!tmpseg.empty())add_seg(tmpseg);
        }
    }
}
int cmp(const point & l, const point & r) {
    if (l.pos != r.pos) return l.pos < r.pos;
    return l.mrk < r.mrk;
}
void sort_seg() {
    sort(points, points + pn, cmp);
}
void calc_max() {
    int i, tot = 0, maxx = 0;
    for (i = 0; i < pn; ++i) {
        if (points.mrk) ++tot; else --tot;
        if (tot > maxx) maxx = tot;
    }
    if (maxx + 2 > best) best = maxx + 2;
}
int main() {
    //freopen("D:\\Contest\\4+2\\2011\\ninjapro\\input1.txt","r", stdin);
    int t, i, j, k;
    scanf("%d", &t);
    while (t--) {
        scanf("%d%d%d", &n, &r, &e);
        for (i=0;i<n;++i) {
            scanf("%lf%lf%lf%lf", &x, &y,&vx, &vy);
        }
        best = 2;
        // enumerate the fixed line
        for (i=0;i<n;++i) {
            for (j=0;j<n;++j) {
                pn = 0;
                if (i == j) continue;
                for (k = 0; k < n; ++k) {
                    if (i == k || j == k) continue;
                    calc_valid_seg(i, j, k);
                }
                sort_seg();
                calc_max();
                //printf("%d %d\n", i,j);
            }
        }
        printf("%d\n", best);
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值