[CF981F] 二分答案 贪心 校内集训 8-2 T2

题目传送门
感谢 x x x h h h 的讲解!!
这是一道很棒的题~~ 模型转化也比较需要思考 
首先这个题可能会无从下手,仔细观察可以发现一个性质,那就是一段新郎一定对应一段连续的新娘,可以用简单证明下,如果存在一个匹配,有一个新郎跨越了另一个新郎的话,那么这肯定不会最优,因为我们可以交换这两个新郎所对应的新娘,使其多出来的一段距离消去,一定会让答案更优。有了这个性质之后我们考虑二分答案,把新娘的序列扩展成三倍,分别代表从左往右跨越起点,从右往左跨越起点和不跨越起点三种情况,把两个序列排序,首先找到第一个新郎能到达的新娘的区间 [ l , r ] ,由于新郎必须连续对应一段新娘,那么下一个新郎能到达的新娘的区间就是 [ l + 1 , r + 1 ] 与自己原本能到达区间的交集, 这样如果存在一个新郎没有选择的区间那么当前答案就是不可行的,否则就是可行的,这样就做完了,复杂度 O ( n l o g L )

Codes

#include<bits/stdc++.h>
#define For(i, a, b) for(register int i = a; i <= b; ++ i)
#define mid ((l + r) >> 1)

using namespace std;

const int maxn = 6e5 + 10, mod = 20000909;
int n, L, a[maxn], b[maxn];

bool check(int x) {
    int l = 1, r = n * 3;
    For(i, 1, n) {
        while(a[i] - b[l] > x)
            ++ l;
        while(b[r] - a[i] > x)
            -- r;
        ++ l, ++ r;
    }
    return l <= r;
}

void File() {
    freopen("queue.in", "r", stdin);
    freopen("queue.out", "w", stdout);
}

void Init() {
    scanf("%d%d", &n, &L);
    For(i, 1, n) scanf("%d", &a[i]);
    For(i, 1, n) {
        scanf("%d", &b[i]);
        b[i + n] = b[i] + L;
        b[i + 2 * n] = b[i] - L;
    }
    sort(a + 1, a + n + 1);
    sort(b + 1, b + n * 3 + 1);
}

void Solve() {
    int l = 0, r = L + 1 >> 1, ans;
    while(l <= r) {
        if(check(mid))
            ans = mid, r = mid - 1;
        else
            l = mid + 1;
    }
    printf("%d\n", qpow(2, ans));
}

int main() {
    File();
    Init();
    Solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/lunch__/article/details/81427905
T2