2020 ICPC Shanghai Site H Rice Arrangement

H Rice Arrangement

题意

有一个有 n n n个座位的桌子,有 k k k个人和 k k k盘菜,通过旋转桌子让每个人都吃且仅吃一道菜问最小旋转角度。

思路

首先引入一个结论

把每个人和对应的手抓饭在圆盘上连线,这些连线是不会相交的

然后设置k层轮转,选择第一个人的菜

然后对于每一个轮转,上面的每一道菜可以分为两类:

  • 通过逆时针旋转到对应的人的口中
  • 通过顺时针寻转到对应的人的口中

每一种轮转的最小答案值就是 m i n ( 2 ∗ m a x C o s t 顺 + m a x C o s t 逆 , m a x C o s t 逆 + 2 ∗ m a x C o s t 顺 ) min(2*maxCost_{顺}+maxCost_{逆},maxCost_{逆}+2*maxCost_{顺}) min(2maxCost+maxCostmaxCost+2maxCost)的最小值

然后贪心考虑,如果选择了最大的顺时针寻转角度为 x x x,那么所有角度在此之前的可以被“免代价”选择,逆时针同理

然后考虑到,除了 C o s t = 0 Cost=0 Cost=0的情况,别的情况下每个点的 C o s t 顺 + C o s t 逆 = k Cost_{顺}+Cost_{逆}=k Cost+Cost=k

所以我们可以按 C o s t 顺 Cost_{顺} Cost来排序,然后枚举分界点计算答案

代码
#include <algorithm>
#include <cmath>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
#define P pair<ll, ll>
int a[maxn], b[maxn];
P dis[maxn];
int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int n, k;
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= k; ++i) {
            scanf("%d", a + i);
        }
        for (int i = 1; i <= k; ++i) {
            scanf("%d", b + i);
        }
        sort(a + 1, a + 1 + k);
        sort(b + 1, b + 1 + k);
        ll ans = 0x3f3f3f3f3f3f3f3f;
        for (int delta = 0; delta < k; ++delta) {
            ll tpans = 0x3f3f3f3f3f3f3f3f;
            ll mx = 0;
            for (int i = 1; i <= k; ++i) {
                dis[i].first = (a[i] - b[(i + delta) % k + 1] + n) % n;
                dis[i].second = n-dis[i].first;
                mx = max(mx, dis[i].second);
            }
            tpans = min(tpans, mx);
            sort(dis + 1, dis + 1 + k);
            dis[k + 1].first = dis[k + 1].second = 0;
            for (int i = 1; i <= k; ++i) {
                tpans = min({tpans, dis[i].first * 2 + dis[i + 1].second,
                             dis[i].first + dis[i + 1].second * 2});
            }
            ans = min(ans, tpans);
        }
        printf("%lld\n", ans);
    }
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值