Codeforces Round#287(Div.2)

1月23日晚上的比赛,放假后的第一场比赛。晚上十一点的时候实在太困了,就想着先去小睡一会儿,定了个闹钟,结果尼玛就睡过头了。。。睡死过去了,半夜两点半才惊醒但是比赛已经结束了。。。汗,真是有点没脑子。早上起来把前三题给做了,哎。。下一场千万不能再睡过去了。。。

A.题目要求不是很苛刻,只要输出正确结果就可以了,但是需要在排序的同时记录好原来各点初始位置,用了结构体。水题能在最短时间想出的方法就是好方法,附代码:

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <algorithm>
#include <cstring>

using namespace std;

struct node{
    int first;
    int second;
    const bool operator < (node next)const
    {
        return this->first < next.first;
    }
};
node T[105];
int save[105];
int main()
{
    int N,D,i,sum;
    scanf("%d%d",&N,&D);
    for( i = 0; i < N; i++ )
    {
        scanf("%d",&T[i].first);
        T[i].second = i+1;
    }
    sort(T,T+N);i = 0;sum = 0;
    while( D >= T[i].first && sum < N)
    {
        save[sum] = T[i].second;
        D-=T[i].first;
        i++;sum++;
    }
    printf("%d\n",sum);
    for( i = 0; i < sum; i++)
        printf("%d ",save[i]);
    printf("\n");
    return 0;
}


B.这次的B题也很简单,在两圆心连线上移动,当两点间距离小于2r时需要明白只需要一次就可以移到目标点了。水过,附代码:

#include <bits/stdc++.h>

using namespace std;

int main()
{
    int times=0;
    double length;
    long long r,x,y,x1,y1;
    scanf("%I64d%I64d%I64d%I64d%I64d",&r,&x,&y,&x1,&y1);
    length=sqrt((double)((x1-x)*(x1-x)+(y1-y)*(y1-y)));
    while( length > 2*r )
    {
        times++;
        length -= 2*r;
    }
    if( length > 0 )
        times++;
    printf("%d\n",times);
    return 0;
}

C.树,因为之前做树的题目很少,所以刚上来虽然觉得很简单但是始终找不到突破口,最开始想用贪心做,但是找不到合适的数据结构。看了学长的代码,使用二分做的,方法很棒。

思路稍微整理一下:题目所描述的方法很容易理解,有一个特点是当进入一个分支后一定会把这个分支遍历完才会到数的另一个分支。所以如果提前判断的话,可以进行很大程度的剪枝。每次到一个节点都可以依据目标点的位置进行一个判断,因为1 <= n <= 2^h 所以,目标点的具体位置通过二分法也可以很好判断。逐层遍历,很快就可以求出答案。附代码:

#include <bits/stdc++.h>

using namespace std;

long long h,n;
long long T[50+10];//存储2^n
long long times;//存储遍历的节点数
bool ini();
int main()
{
    cin>>h>>n;
    ini();
    times=0;
    bool flag=true;//标记,决定向左或向右
    long long left,mid,right;
    left = 1;right = T[h];//确定边界
    for( int i = 0; i < h; i++)
    {
        mid = (left + right)/2;
        if( flag )
        {
            flag = false;
            if( n >= left && n <= mid )
            {
                times++;
                right = mid;
            }
            else
            {
            //此种情况剪枝,直接加上左边一颗小树 以及右边数的根节点,表达式如下:
            //1+(1*(2^n-1))/(2-1)=2^n
            //n为树的高度,即h-i
                times += T[h-i];
                left = mid;
                flag = true;
            }
        }
        else
        {
            flag = true;
            if( n >= mid + 1 && n <= right)
            {
                times++;
                left = mid;
            }
            else
            {
                times += T[h-i];
                right = mid;
                flag = false;
            }
        }
    }
    printf("%I64d\n",times);
    return 0;
}
bool ini()
{
    memset(T,0,sizeof(T));
    T[0]=1;
    for( int i = 1; i < 60; i++ )
        T[i] = T[i-1]*2;
    return true;
}

这次的比赛还是比较简单的,但是就是睡过去了。。。。。三天后的比赛要长点心了,骚年。。


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值