2021牛客暑期多校训练营6

2021牛客暑期多校训练营6

F-Hamburger Steak

思路

按照时间长短降序排序,并计算 a n s b e s t = m a x ( ⌈ a v g ( t i ) ⌉ , m a x { t i } ) ans_{best} = max(\lceil avg(t_i) \rceil , max\{t_i\}) ansbest=max(avg(ti),max{ti}) ,之后按照时间降序安排锅中汉堡的时间,若当前锅时间已经超过 a n s b e s t ans_{best} ansbest ,就换到下一锅进行安排并截掉超出的那部分放入下一锅,这样可以完全满足题意(汉堡不能同时放在两个锅里)并且时间最短。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e5 + 10;
const int mod = 998244353;

struct node
{
    ll l, r;
    int id;
    bool operator < (const node& obj) const
    {
        return l < obj.l;
    }
};

struct node1
{
    int id;
    ll num;
    bool operator < (const node1& obj) const
    {
        return num > obj.num;
    }
};

node1 t[N];

vector<node> vec[N];

int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    ll sum = 0;
    for(int i = 0; i < n; i++)
    {
        scanf("%lld", &t[i].num);
        t[i].id = i;
        sum += t[i].num;
    }
    ll best = (sum + m - 1) / m;
    sort(t, t + n);
    if(t[0].num > best)
        best = t[0].num;
    int id = 1;
    ll cnt = 0;
    for(int i = 0; i < n; i++)
    {
        if(cnt + t[i].num > best)
        {
            vec[t[i].id].push_back({cnt, best, id});
            t[i].num = t[i].num - best + cnt;
            cnt = 0;
            id++;
            i--;
        }
        else
        {
            vec[t[i].id].push_back({cnt, cnt + t[i].num, id});
            cnt += t[i].num;
            if(cnt == best)
            {
                cnt = 0;
                id++;
            }
        }
    }
    for(int i = 0; i < n; i++)
    {
        node t1, t2;
        if(vec[i].size() == 1)
        {
            t1 = vec[i][0];
            cout << 1 << ' ';
            cout << t1.id << ' ' << t1.l << ' ' << t1.r << endl;
        }
        else
        {
            t1 = vec[i][0];
            t2 = vec[i][1];
            cout << 2 << ' ';
            if(t2.l > t1.l)
            {
                cout << t1.id << ' ' << t1.l << ' ' << t1.r << ' ';
                cout << t2.id << ' ' << t2.l << ' ' << t2.r << endl;
            }
            else
            {
                cout << t2.id << ' ' << t2.l << ' ' << t2.r << ' ';
                cout << t1.id << ' ' << t1.l << ' ' << t1.r << endl;
            }
        }
    }
    return 0;
}

H-Hopping Rabbit

思路

其实从 ( x , y ) (x, y) (x,y) 点出发和从 ( x + d , y + d ) (x + d, y + d) (x+d,y+d) 出发是一样的,因为左右都只能跳 d d d 的距离,那么有区别的出发点其实都可以归纳到 x ∈ [ 0 , d ) , y ∈ [ 0 , d ) x \in [0, d), y \in [0, d) x[0,d),y[0,d) 的范围内。我们把所有的陷阱都通过这种方法映射到 x ∈ [ 0 , d ) , y ∈ [ 0 , d ) x \in [0, d), y \in [0, d) x[0,d),y[0,d) 的范围内(赋值为1),然后找任意一个值为0的点输出其坐标即可,若没有这样的点就是不可行。

听起来很简单,但是d的范围1e5,暴力显然不行。开始觉得用二维线段树也可以做,奈何不会,后来在想“什么数据结构可以用来处理矩形覆盖问题”的时候,突然想到扫描线。扫描线扫的过程中查找是不是有某一列的值不是满的,若有就说明该列有0,若无则没有答案。若找到了某个有0的列,就将其之前的所有线段开头结尾在一个初始为0的数组中标记(开头+1,结尾-1),最后 O ( n ) O(n) O(n) 求一遍前缀和就可以知道在修改到该列时,整列的状态,此时若有前缀和为0的位置,就是我们要找的答案。这样的复杂度是 O ( log ⁡ d + d ) O(\log d + d) O(logd+d)​ ,是可以通过的。

不过好像题目数据有点弱,我们漏判了开头到第一个矩形的部分,居然过了。

代码

赛后自己重新写了一遍,完美复现了赛场上的所有错误(不是)

被负数取模坑了几个小时,好像这个细节还是我在赛场上提出来的,转头就忘不愧是我()

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;

int n;
struct Segment
{
    ll x, y1, y2;
    int k;
    bool operator < (const Segment& t) const
    {
        return x < t.x;
    }
} seg[N * 8];

struct node
{
    int l, r;
    ll cnt;
    ll len;
} tr[N * 16];

vector<int> ys;

int find(int y)
{
    return lower_bound(ys.begin(), ys.end(), y) - ys.begin();
}

void pushup(int u)
{
    if(tr[u].cnt)
        tr[u].len = ys[tr[u].r + 1] - ys[tr[u].l];
    else if(tr[u].l != tr[u].r)
        tr[u].len = tr[u << 1].len + tr[u << 1 | 1].len;
    else
        tr[u].len = 0;
}

void build(int u, int l, int r)
{
    tr[u] = {l, r, 0, 0};
    if(l != r)
    {
        int mid = (l + r) >> 1;
        build(u << 1, l, mid);
        build(u << 1 | 1, mid + 1, r);
    }
}

void modify(int u, int l, int r, int k)
{
    if(tr[u].l >= l && tr[u].r <= r)
    {
        tr[u].cnt += k;
        pushup(u);
    }
    else
    {
        int mid = (tr[u].l + tr[u].r) >> 1;
        if(l <= mid)
            modify(u << 1, l, r, k);
        if(r > mid)
            modify(u << 1 | 1, l, r, k);
        pushup(u);
    }
}

int f[N];

int main()
{
    int n, d, j = 0;
    scanf("%d%d", &n, &d);
    bool flag = 0;
    seg[j++] = {0, 0, d, 0};
    seg[j++] = {d, 0, d, 0};
    ll add = 1e9 * d;
    for(int i = 0; i < n; i++)
    {
        ll x1, y1, x2, y2;
        scanf("%lld%lld%lld%lld", &x1, &y1, &x2, &y2);
        if(x2 - x1 >= d && y2 - y1 >= d)
        {
            flag = 1;
            break;
        }
        x1 += add;
        x2 += add;
        y1 += add;
        y2 += add;

        x1 %= d;
        y1 %= d;
        x2 = (x2 - 1 + d) % d + 1;
        y2 = (y2 - 1 + d) % d + 1;
        if(x1 < x2)
        {
            if(y1 < y2)
            {
                seg[j++] = {x1, y1, y2, 1};
                seg[j++] = {x2, y1, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
            }
            else if(y1 > y2) // [y1, d) + [0, y2)
            {
                seg[j++] = {x1, y1, d, 1};
                seg[j++] = {x2, y1, d, -1};
                seg[j++] = {x1, 0, y2, 1};
                seg[j++] = {x2, 0, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
                ys.push_back(0);
                ys.push_back(d);
            }
            else
            {
                seg[j++] = {x1, 0, d, 1};
                seg[j++] = {x2, 0, d, -1};
                ys.push_back(0);
                ys.push_back(d);
            }
        }
        else if(x1 > x2)
        {
            if(y1 < y2) // [x1, d) + [0, x2)
            {
                seg[j++] = {x1, y1, y2, 1};
                seg[j++] = {d, y1, y2, -1};
                seg[j++] = {0, y1, y2, 1};
                seg[j++] = {x2, y1, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
            }
            else if(y1 > y2) // [x1, d) + [0, x2) + [y1, d) + [0, y2)
            {
                seg[j++] = {x1, y1, d, 1};
                seg[j++] = {d, y1, d, -1};
                seg[j++] = {0, y1, d, 1};
                seg[j++] = {x2, y1, d, -1};
                seg[j++] = {x1, 0, y2, 1};
                seg[j++] = {d, 0, y2, -1};
                seg[j++] = {0, 0, y2, 1};
                seg[j++] = {x2, 0, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
                ys.push_back(0);
                ys.push_back(d);
            }
            else
            {
                seg[j++] = {x1, 0, d, 1};
                seg[j++] = {d, 0, d, -1};
                seg[j++] = {0, 0, d, 1};
                seg[j++] = {x2, 0, d, -1};
                ys.push_back(0);
                ys.push_back(d);
            }
        }
        else
        {
            if(y1 < y2)
            {
                seg[j++] = {0, y1, y2, 1};
                seg[j++] = {d, y1, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
            }
            else if(y1 > y2) // [y1, d) + [0, y2)
            {
                seg[j++] = {0, y1, d, 1};
                seg[j++] = {d, y1, d, -1};
                seg[j++] = {0, 0, y2, 1};
                seg[j++] = {d, 0, y2, -1};
                ys.push_back(y1);
                ys.push_back(y2);
                ys.push_back(0);
                ys.push_back(d);
            }
            else
            {
                flag = 1;
                break;
            }
        }
    }

    if(flag)
    {
        printf("NO\n");
        return 0;
    }

    int cnt = j;
    sort(seg, seg + cnt);
    sort(ys.begin(), ys.end());
    ys.erase(unique(ys.begin(), ys.end()), ys.end());

    build(1, 0, ys.size() - 2);

    int res = 0;

    int pos = -1;

    for(int i = 0; i < cnt; i++)
    {
        if(i > 0)
        {
            int h = seg[i].x - seg[i - 1].x;
            int w = tr[1].len;
            if(h && w < d)
            {
                pos = i;
                break;
            }
            if(seg[i].k)
                modify(1, find(seg[i].y1), find(seg[i].y2) - 1, seg[i].k);
        }
    }
    if(pos == -1)
    {
        printf("NO\n");
        return 0;
    }
    for(int i = 0; i < pos; i++)
    {
        f[seg[i].y1] += seg[i].k;
        f[seg[i].y2] -= seg[i].k;
    }
    int y = -1;
    for(int i = 0; i < d; i++)
    {
        if(i > 0)
            f[i] = f[i - 1] + f[i];
        if(f[i] == 0)
        {
            y = i;
            break;
        }
    }
    if(y == -1)
    {
        printf("NO\n");
        return 0;
    }
    int x = seg[pos - 1].x;
    printf("YES\n%d %d\n", x, y);
    return 0;
}

I-Intervals on the Ring

思路

设要凑出的集合为 [ l 1 , r 1 ] , [ l 2 , r 2 ] , … , [ l n , r n ] {[l_1, r_1], [l_2, r_2], \dots, [l_n, r_n]} [l1,r1],[l2,r2],,[ln,rn]​ ,则答案序列为 [ l 1 , r n ] , [ l 2 , r 1 ] , [ l 3 , r 2 ] , … , [ l n , r n − 1 ] {[l_1, r_n], [l_2, r_1], [l_3, r_2], \dots, [l_n, r_{n - 1}]} [l1,rn],[l2,r1],[l3,r2],,[ln,rn1]​ 。​​​

注意输入可能会有一个 l > r l > r l>r 的情况,这个要分两个处理。

显然是不会不存在的。

代码

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF = 0x3f3f3f3f;
const int N = 1e6 + 10;
const int mod = 998244353;

struct node
{
    int l, r;
    bool operator < (const node& obj) const
    {
        return l < obj.l;
    }
};

vector<node> vec;

int main()
{
    int T;
    scanf("%d", &T);
    while(T--)
    {
        vec.clear();
        int n, m;
        scanf("%d%d", &n, &m);
        for(int i = 0, l, r; i < m; i++)
        {
            scanf("%d%d", &l, &r);
            if(l > r)
            {
                vec.push_back({l, n});
                vec.push_back({1, r});
            }
            else
            {
                vec.push_back({l, r});
            }
        }
        sort(vec.begin(), vec.end());
        printf("%d\n", vec.size());
        printf("%d %d\n", vec[0].l, vec[vec.size() - 1].r);
        for(int i = 1; i < vec.size(); i++)
        {
            printf("%d %d\n", vec[i].l, vec[i - 1].r);
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值