Codeforces Round #128

本文解析了五道ACM竞赛题目,包括简单的数学问题、动态规划、贪心算法、物理模拟及复杂的机器人路径规划问题。提供了详细的算法思路及C++实现代码。

Problem A

水题,不解释,注意可以只做出一题或者一题都没做。

Problem B

水题,怎么样YY都可以,用一个数组dp[i][j]保存以(i,j)为左上角构成的边长为3的正方形有几个涂黑,然后每次更新时顺便判断是否有更新到9。

Problem C

贪心。肯定是尽量服务内存需求小的客户,才能使服务的客户数尽量多,因此排序之后贪心。

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

typedef struct
{
    int num;
    __int64 val;
}C;

C p[100005];

bool cmp(C x,C y)
{
    return x.val<y.val;
}

int main()
{
    int i,j,n,x,y,a,b;
    __int64 m,s;
    scanf("%d%I64d",&n,&m);
    scanf("%d%d",&a,&b);
    for (i=0;i<n;i++)
    {
        scanf("%d%d",&x,&y);
        p[i].val=x*a+y*b;
        p[i].num=i+1;
    }
    sort(p,p+n,cmp);
    s=0;
    for (i=0;i<n;i++)
    {
        s+=p[i].val;
        if (s>m) break;
    }
    j=i;
    printf("%d\n",j);
    if (j==0) return 0;
    for (i=0;i<j-1;i++)
    {
        printf("%d ",p[i].num);
    }
    printf("%d\n",p[i].num);
    return 0;
}

Problem D

物理题,给定小球的初始位置和初速度,在经过各种碰撞后到达Xoz后的位置。

分别对x方向和z方向求解。

对于x方向,因为小球经过2*a为一循环,因此在对a取模后判断方向和剩下飞行的路程,即可得到最终位置,同理可求z方向上的。

答案是0时输出-0.00000居然会WA?

#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;

typedef struct
{
    double x,y,z;
}Vector;

int main()
{
    int i,j,t;
    double a,b,m,vx,vy,vz,last;
    Vector now,v;
    scanf("%lf%lf%lf",&a,&b,&m);
    scanf("%lf%lf%lf",&v.x,&v.y,&v.z);
    now.x=a/2;
    now.y=m;
    now.z=0;
    t=(int)(v.x*m/(-v.y)/a);
    last=v.x*m/(-v.y)-a*t;
    if (t%2==0)
    {
        if (last<=now.x) printf("%lf ",fabs(now.x+last));
        else printf("%lf ",fabs(a-(last-now.x)));
    }
    else
    {
        if (last<=now.x) printf("%lf ",fabs(now.x-last));
        else printf("%lf ",fabs(last-now.x));
    }
    t=(int)(v.z*m/(-v.y)/b);
    last=v.z*m/(-v.y)-b*t;
    if (t%2==0)
    {
        printf("%lf\n",fabs(last));
    }
    else
    {
        printf("%lf\n",fabs(b-last));
    }
    return 0;
}


Problem E

昨天的比赛过了前四题,第五题没时间了,前面各种乱YY乱交……orz

该题题意给定一些机器人,每个机器人有三个属性,可载机器人数、耗油量、自动行走路程。问给定最多S升汽油,问能够让最多多少个机器人行走l距离,耗油量最少是多少。

先预处理,将自动行走路程不到l的机器人耗油量设置大于S的值,这样就将两种不能自己行走过去的情况(汽油 >S、路程<l)合成一种情况了。

两种情况,第一种情况是没有机器人载机器人的情况出现,那么就按照耗油量从小到大排序,然后从小到大选机器人。

第二种情况就是有机器人载机器人的情况出现,如果让机器人互相搭载上,而让其中一个机器人作为根,即在底下行走的机器人,那么总共可以搭载sigma(carry.c[i])+1,其中sigma(carry.c[i])为所有可以搭载的机器人的搭载数量之和。

如果这个和大于n,那么所有机器人都可以走了,如果小于n,那么就需要选择除了根之外的耗油最小的机器人,作为一个新的根,如果这个根在前面已经被搭载上了,则把它拉出来做个新根,而放一个耗油更大的机器人顶替他的位置。

因此答案就是sigma(carry.c[i])+1,再加上除了根之外根据耗油量从小到大一直加直到所有根的耗油量之和大于s或者答案为n时为止。


代码

#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;

typedef struct
{
    __int64 c,f,l;
}Robot;

Robot a[100005];
Robot carry[100005];
Robot ncarry[100005];

bool cmp(Robot x,Robot y)
{
    return x.f<y.f;
}

int main()
{
    int i,j,n,n1,n2;
    __int64 d,s,sum,f1,f2,ans1,ans2;
    scanf("%d%I64d%I64d",&n,&d,&s);
    n1=n2=sum=0;
    for (i=0;i<n;i++)
    {
        scanf("%I64d%I64d%I64d",&a[i].c,&a[i].f,&a[i].l);
        if (a[i].c!=0)
        {
            if (a[i].l<d) a[i].f=s+1;
            carry[n1++]=a[i];
            sum+=a[i].c;
        }
        else
        {
            if (a[i].l<d) a[i].f=s+1;
            ncarry[n2++]=a[i];
        }
    }
    sort(carry,carry+n1,cmp);
    sort(ncarry,ncarry+n2,cmp);
    for (i=0;i<n;i++)
    {
        if (carry[0].f==a[i].f && carry[0].l==a[i].l && carry[0].c==a[i].c) break;
    }
    swap(a[i],a[n-1]);
    sort(a,a+n-1,cmp);
    ans1=0;
    f1=0;
    for (i=0;i<n2;i++)
    {
        if (f1+ncarry[i].f<=s)
        {
            ans1++;
            f1+=ncarry[i].f;
        }
    }
    ans2=0;
    f2=0;
    if (n1>0 && carry[0].f<=s)
    {
        ans2=min((__int64)n,sum+1);
        f2=carry[0].f;
        for (i=0;i<n-1;i++)
        {
            if (ans2<n && f2+a[i].f<=s)
            {
                ans2++;
                f2+=a[i].f;
            }
        }
    }
    if (ans1>ans2) printf("%I64d %I64d\n",ans1,f1);
    else if (ans1<ans2) printf("%I64d %I64d\n",ans2,f2);
    else if (f1>f2) printf("%I64d %I64d\n",ans2,f2);
    else printf("%I64d %I64d\n",ans1,f1);
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值