[SMOJ1043]选凳子 ( 2016 创新班 )

本文介绍了一道编程题目,涉及无限数量的凳子和奶牛选择凳子的问题。每只奶牛选择凳子时要考虑左右D距离内不能有其他奶牛,并且编号要大于等于自身。题目提供了输入输出格式和样例,讨论了解决方案,包括尝试使用线段树和最终的 O(n^2 log n) 时间复杂度的算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述

从左往右有无限多张凳子,凳子的编号从左往右依次是:1,2,3,4,5,6……。有 N 只奶牛排着队正走过来,N 只奶牛的编号分别用1,2,3,4,… N 来表示。它们要找合适的凳子坐。每只奶牛选择凳子的规则都是:

  1. 奶牛都不喜欢太拥挤,于是奶牛选择的凳子左边 D 距离内不能有其它奶牛坐,右边 D 距离内也不能有奶牛坐。比如:两头奶牛,当 D =10时,一只奶牛选择编号是47的凳子,另一只选择编号是57的凳子,这是合法的。当 D =10时,一只奶牛选择编号是47的凳子,另一只选择编号是56的凳子,这是不合法的,因为他们之间的距离小于10。
  2. 对于第 i 只奶牛来说,它选择的凳子的编号必须大于或等于 Ai
    • 在满足第(1)、第(2)点的前提下,奶牛会尽量选择编号小的凳子坐下来。
    • 现在这 N 只奶牛按照编号从小到大的顺序排好了队,编号是1的奶牛排在最前面,它首先按照如上的规则选好凳子后就坐下来,接着是编号是2的奶牛选择凳子后坐下来,接着是编号是3的奶牛选择凳子后坐下来 ,……最后选择凳子的奶牛是第 N 只奶牛。
      你的任务是:输出编号是1至 N 的奶牛,它们各自选择的凳子的编号。

输入格式 1043.in

多组测试数据。
第一行,一个整数 R,表示有 R 组测试数据。1R6
每组测试数据格式如下:
第一行,两个正整数,ND1N10001D106
第二行,N 个整数,第 i 个整数表示 Ai1Ai106

输出格式 1043.out

R 行,每行对应一组测试数据。
每组测试数据的输出都是一行,该行包含 N 个整数,空格分开,第 i 个整数表示第 i 只奶牛选择的凳子的编号。

输入样例 1043.in

5
4 10
1 21 11 7
4 11
1 21 11 7
4 1000000
1000000 1000000 1000000 1
4 999999
1000000 1000000 1000000 1
4 1
8 7 5 1

输出样例 1043.out

1 21 11 31
1 21 32 43
1000000 2000000 3000000 4000000
1000000 1999999 2999998 1
8 7 5 1


最近做多了线段树的题,第一反应就是写个线段树维护一下凳子被占用的情况,似乎是可行的,只是没有注意到数据范围。而且有无限多张椅子,理论上是不可能在真正意义上实现的。样例在本地过了,一提交却 MLE 。

于是又想起 lws 的最高指示:“数据量决定算法。”发现牛的数量其实是很少的,可以从这一点入手。

也就是说,对于每一头牛,都可以将其与之前已经安排好位置的牛进行对比,从而选出合适的位置。但在对比时要注意,之前的奶牛要按顺序排好,否则可能会出现为了满足后面的奶牛但却与前面的奶牛冲突的情况。因此每确定一头奶牛的位置都重新排一次序,总的时间复杂度为 O(n2log2n)

参考代码:

#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>

using namespace std;

const int maxn = 1e6 + 10;

int a[maxn], b[maxn];

int main(void) {
    freopen("1043.in", "r", stdin);
    freopen("1043.out", "w", stdout);
    int r;
    scanf("%d", &r);
    while (r--) {
        int n, d;
        scanf("%d%d", &n, &d);
        for (int i = 0; i < n; i++) scanf("%d", &a[i]);
        for (int i = 0; i < n; i++) {
            b[i] = a[i];
            for (int j = 0; j < i; j++)
                if (abs(b[i] - b[j]) < d) b[i] = b[j] + d;
            printf("%d ", b[i]);
            sort(b, b + i + 1);
        }
        putchar('\n');
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值