Codeforces 309E - Sheep(二分+贪心)
为啥感觉这种跟区间有关的贪心我都不太会做啊/dk
考虑二分答案 ,任务转化为检验是否存在一个排列满足对于序列中任意两个相交的区间,它们在排列中的距离都 ,并顺带找出一个符合要求的排列。
我们考虑一个贪心的策略:按位置从小到大钦定所有区间的位置。对每个区间维护一下这一区间最远可以放在那里,设为 ,也就是说这一区间在序列中的位置必须 ,那么假设当前钦定了前 个位置上的值,我们开一个桶 维护有多少个 并统计 的前缀和 ,显然根据 Hall 定理,如果存在一个 满足 ,就无解,否则我们求出 且最小的 ,那么显然我们在第 步放置的区间 必须满足 ——否则下一步就不符合 的要求了,而我们又尽量希望这个区间尽量不与其他区间相交,因此我们要求该区间右端点尽可能小,也就是说找出 且 最小的区间放在 ,然后更新其他区间的 即可。感性理解一下可知该算法正确性。
时间复杂度 。
#include <bits/stdc++.h> //#include <ext/pb_ds/assoc_container.hpp> //#include <ext/pb_ds/hash_policy.hpp> using namespace std; //using namespace __gnu_pbds; #define fi first #define se second #define fill0(a) memset(a, 0, sizeof(a)) #define fill1(a) memset(a, -1, sizeof(a)) #define fillbig(a) memset(a, 63, sizeof(a)) #define pb push_back #define ppb pop_back #define mp make_pair #define mt make_tuple #define eprintf(...) fprintf(stderr, __VA_ARGS__) template <typename T1, typename T2> void chkmin(T1 &x, T2 y){ if (x > y) x = y; } template <typename T1, typename T2> void chkmax(T1 &x, T2 y){ if (x < y) x = y; } typedef pair<int, int> pii; typedef long long ll; typedef unsigned int u32; typedef unsigned long long u64; typedef long double ld; namespace fastio { #define FILE_SIZE 1 << 23 char rbuf[FILE_SIZE], *p1 = rbuf, *p2 = rbuf, wbuf[FILE_SIZE], *p3 = wbuf; inline char getc() { return p1 == p2 && (p2 = (p1 = rbuf) + fread(rbuf, 1, FILE_SIZE, stdin), p1 == p2) ? -1: *p1++; } inline void putc(char x) {(*p3++ = x);} template <typename T> void read(T &x) { x = 0; char c = getc(); T neg = 0; while (!isdigit(c)) neg |= !(c ^ '-'), c = getc(); while (isdigit(c)) x = (x << 3) + (x << 1) + (c ^ 48), c = getc(); if (neg) x = (~x) + 1; } template <typename T> void recursive_print(T x) { if (!x) return; recursive_print (x / 10); putc (x % 10 ^ 48); } template <typename T> void print(T x) { if (!x) putc('0'); if (x < 0) putc('-'), x = -x; recursive_print(x); } template <typename T> void print(T x,char c) {print(x); putc(c);} void readstr(char *s) { char c = getc(); while (c <= 32 || c >= 127) c = getc(); while (c > 32 && c < 127) s[0] = c, s++, c = getc(); (*s) = 0; } void printstr(string s) { for (int i = 0; i < s.size(); i++) putc(s[i]); } void printstr(char *s) { int len = strlen(s); for (int i = 0; i < len; i++) putc(s[i]); } void print_final() {fwrite(wbuf, 1, p3 - wbuf, stdout);} } const int MAXN = 2000; const int INF = 0x3f3f3f3f; int n, ans[MAXN + 5], l[MAXN + 5], r[MAXN + 5], pos[MAXN + 5], vis[MAXN + 5]; bool check(int mid) { memset(vis, 0, sizeof(vis)); for (int i = 1; i <= n; i++) pos[i] = n; for (int i = 1; i <= n; i++) { static int buc[MAXN + 5]; memset(buc, 0, sizeof(buc)); for (int j = 1; j <= n; j++) if (!vis[j]) buc[pos[j]]++; for (int j = 1; j <= n; j++) buc[j] += buc[j - 1]; for (int j = 1; j <= n; j++) if (buc[j] > max(j - i + 1, 0)) return 0; int nw = 0, nd_lim = n; for (int j = n; j >= i; j--) if (buc[j] == j - i + 1) nd_lim = j; for (int j = 1; j <= n; j++) if (!vis[j] && r[j] < r[nw] && pos[j] <= nd_lim) nw = j; ans[i] = nw; vis[nw] = 1; // printf("! %d\n", nw); for (int j = 1; j <= n; j++) if (!vis[j] && max(l[j], l[nw]) <= min(r[j], r[nw])) chkmin(pos[j], i + mid); // for (int j = 1; j <= n; j++) printf("%d%c", pos[j], " \n"[j == n]); // for (int j = 1; j <= n; j++) printf("%d%c", vis[j], " \n"[j == n]); } return 1; } int main() { scanf("%d", &n); r[0] = INF; for (int i = 1; i <= n; i++) scanf("%d%d", &l[i], &r[i]); int L = 0, R = n - 1, p = 0; // check(1); while (L <= R) { int mid = L + R >> 1; if (check(mid)) p = mid, R = mid - 1; else L = mid + 1; } // printf("%d\n", p); check(p); for (int i = 1; i <= n; i++) printf("%d%c", ans[i], " \n"[i == n]); return 0; }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
2021-02-10 数论学习笔记
2021-02-10 洛谷 P7323 - [WC2021] 括号路径(启发式合并)