2021 RoboCom 世界机器人开发者大赛-本科组(初赛)芬兰木棋(30分)(肥肠煎蛋亿学就会ORZ

WX20200212-152528.png

芬兰木棋(Mölkky,又称芬兰木柱)是源自芬兰的一项运动。哲哲将这个运动改造成了赛博朋克单人版,现在场上一开始有 N 根立起的小木棋(上面分别标有一个非负整数),哲哲投掷一根大木棋去击倒这些小木棋以获得分数。分数规则如下:

  • 如果仅击倒 1 根木棋,则得木棋上的分数。
  • 如果击倒 2 根或以上的木棋,则只得击倒根数的分数。(例如击倒 5 根,则得 5 分。)

哲哲固定站在 (0,0) 点上,四周放着若干个小木棋 (Xi​,Yi​),坐标均为整数。每次哲哲可以朝一个方向扔出大木棋,大木棋会打倒这个方向上离哲哲最近的 k 个小木棋。哲哲游戏水平很高超,所以这个 k 可以自由控制。

请问哲哲最多能拿多少分,在获得最多分数的情况下最少需要扔出多少次大木棋?

规则与真实规则有较大出入,真实游玩时请以国际莫尔基组织的规则为准

输入格式:

输入第一行是一个正整数 N (1 ≤ N ≤ 105),表示场上一开始有 N 个木棋。

接下来 N 行,每行 3 个整数 Xi​,Yi​,Pi​,分别表示木棋放置在 (Xi​,Yi​),木棋上的分数是 Pi​。坐标在 32 位整数范围内,分数为小于等于 1000 的正整数。

保证 (0,0) 点没有木棋,也没有木棋重叠放置。

输出格式:

输出一行两个数,表示最多分数以及获得最多分数最少需要投掷大木棋多少次。

输入样例:

11
1 2 2
2 4 3
3 6 4
-1 2 2
-2 4 3
-3 6 4
-1 -2 1
-2 -4 1
-3 -6 1
-4 -8 2
2 -1 999

输出样例:

1022 9

思路:

经典斜率的遍历问题,出了老多次了,我们用map去存化简后的斜率的分母和分子,然后第二个map记录x轴的位置,那么我们就可以得出这个点了,然后我们已知需要最多分数那么我需要把得分大于1的木牌都进行单独击倒,而等于1的木牌如果可以的话连续击倒,我们就可以得出最大分数和最小次数(注意特判X和Y轴!!!!)

代码

#include<bits/stdc++.h>

using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
#define endl '\n'
const int N = 2e5 + 5;
const int inf = 0x3f3f3f3f3f3f3f3f;
int n, m, k, t;
struct node {
    int x, y, w;
    int tx, ty;
} x[N];
map<pair<int, int>, map<int, int>> mp;
//斜率-----位置------应该连击还是单独
map<int, int> mp1, mp2;
//x轴y轴

signed main() {
    cin >> n;
    int ans = 0;
    int num = 0;
    for (int i = 0; i < n; i++) {
        cin >> x[i].x >> x[i].y >> x[i].w;
        ans += x[i].w;
        int tx = x[i].x;
        int ty = x[i].y;
        if (x[i].x == 0) {//y轴
            if (x[i].w != 1)mp1[x[i].y] = 2;
            else mp1[x[i].y] = 1;
            continue;
        }
        if (x[i].y == 0) {//x轴
            if (x[i].w != 1)mp2[x[i].x] = 2;
            else mp2[x[i].x] = 1;
            continue;
        }
        //其余部分(分母分子化简)
        int op = __gcd(tx, ty);
        tx /= op;
        ty /= op;
        x[i].tx = tx;
        x[i].ty = ty;
        if (x[i].w != 1) {
            mp[{x[i].tx, x[i].ty}][x[i].x] = 2;
        } else {
            mp[{x[i].tx, x[i].ty}][x[i].x] = 1;
        }
    }
    int f = 0;
    int flag = 0;
    for (auto it: mp) {//遍历全图
        f = 0;
        flag = 0;
        for (auto i: it.second) {
            if (i.first < 0) {// x轴为负数
                if (i.second == 1) {
                    f = 1;
                } else {
                    num++;
                    if (f == 1) {
                        num++;
                    }
                    f = 0;
                }
            } else {//x轴为正数
                if (flag == 0) {//第一次进入正数的时候需要去清理f
                    if (f == 1)num++;
                    f = 0;
                }
                flag = 1;
                if (i.second == 1) {
                    f = 1;
                } else {
                    num++;
                    if (f == 1) {
                        num++;
                    }
                    f = 0;
                }
            }
        }
        if (f == 1)num++;
    }
    f = 0;
    flag = 0;
    for (auto it: mp1) {//跑y轴
        if (it.first < 0) {
            if (it.second == 1) {
                f = 1;
            } else {
                num++;
                if (f == 1) {
                    num++;
                }
                f = 0;
            }
        } else {
            if (flag == 0) {
                if (f == 1)num++;
                f = 0;
            }
            flag = 1;
            if (it.second == 1) {
                f = 1;
            } else {
                num++;
                if (f == 1) {
                    num++;
                }
                f = 0;
            }
        }
    }
    if(f==1)num++;
    f=0;
    flag=0;
    for (auto it: mp2) {//跑x轴
        if (it.first < 0) {
            if (it.second == 1) {
                f = 1;
            } else {
                num++;
                if (f == 1) {
                    num++;
                }
                f = 0;
            }
        } else {
            if (flag == 0) {
                if (f == 1)num++;
                f = 0;
            }
            flag = 1;
            if (it.second == 1) {
                f = 1;
            } else {
                num++;
                if (f == 1) {
                    num++;
                }
                f = 0;
            }
        }
    }
    if(f==1)num++;
    cout << ans << ' ' << num << endl;
    return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值