简单说一下。
A
搜索出任意一个剩余细胞个数的联通块。剩下的填X。
B
二分加贪心加数据结构。
/* * Problem: * Author: Shun Yao */ #include <string.h> #include <stdlib.h> #include <limits.h> #include <assert.h> #include <stdio.h> #include <ctype.h> #include <math.h> #include <time.h> #include <map> #include <set> #include <list> #include <stack> #include <queue> #include <deque> #include <string> #include <vector> #include <bitset> #include <utility> #include <iomanip> #include <numeric> #include <sstream> #include <iostream> #include <algorithm> #include <functional> //using namespace std; const int MAXN = 100010, MAXM = 100010; int n, m, s, a[MAXM], ai[MAXM], b[MAXN], c[MAXN], bc[MAXN]; bool cmpa(int x, int y) { return a[x] < a[y]; } bool cmpb(int x, int y) { return b[x] < b[y]; } class cmpc { public: bool operator () (int x, int y) { return c[x] > c[y]; } } ; bool check(int x) { std::priority_queue<int, std::vector<int>, cmpc> pq;//小根堆 int i, j = n, k = 0; for (i = m; i >= 1; i -= x) { while (j >= 1 && b[bc[j]] >= a[ai[i]]) { pq.push(bc[j]); --j; } if (pq.empty()) return 0; k += c[pq.top()]; pq.pop(); if (k > s) return 0; } return 1; } void output(int x) { puts("YES"); std::priority_queue<int, std::vector<int>, cmpc> pq; int i = m, j = n, k, ans[MAXM]; while (i >= 1) { while (j >= 1 && b[bc[j]] >= a[ai[i]]) { pq.push(bc[j]); --j; } for (k = 1; k <= x && i >= 1; ++k, --i) ans[ai[i]] = pq.top(); pq.pop(); } for (i = 1; i <= m; ++i) printf("%d ", ans[i]); } int main(/*int argc, char **argv*/) { int i, l, r, mid; scanf("%d%d%d", &n, &m, &s); for (i = 1; i <= m; ++i) { scanf("%d", a + i); ai[i] = i; } for (i = 1; i <= n; ++i) { scanf("%d", b + i); bc[i] = i; } for (i = 1; i <= n; ++i) scanf("%d", c + i); std::sort(ai + 1, ai + m + 1, cmpa); std::sort(bc + 1, bc + n + 1, cmpb); if (!check(m)) printf("NO"); else { l = 1; r = m; while (l < r) { mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } output(r); } fclose(stdin); fclose(stdout); return 0; }
C
贪心,dp,位运算。
/* * Problem: C. Captains Mode * Author: Shun Yao */ #include <string.h> #include <stdlib.h> #include <limits.h> #include <assert.h> #include <stdio.h> #include <ctype.h> #include <math.h> #include <time.h> #include <map> #include <set> #include <list> #include <stack> #include <queue> #include <deque> #include <string> #include <vector> #include <bitset> #include <utility> #include <iomanip> #include <numeric> #include <sstream> #include <iostream> #include <algorithm> #include <functional> //using namespace std; int n, m, a[111], d[21], p[1048577], f[1048577]; char c[21]; int main(/*int argc, char **argv*/) { int i, j, x, y; scanf("%d", &n); for (i = 1; i <= n; ++i) scanf("%d", a + i); std::sort(a + 1, a + n + 1, std::greater<int>()); scanf("%d", &n); for (i = 1; i <= n; ++i) scanf(" %c %d", c + i, d + i); m = (1 << n) - 1; p[0] = 0; for (i = 1; i <= m; ++i) p[i] = p[i >> 1] + (i & 1); f[m] = 0; for (i = m - 1; i >= 0; --i) { f[i] = d[x = p[i] + 1] == 2 ? INT_MAX : INT_MIN; for (j = 1; j <= n; ++j) { y = 1 << (j - 1); if (i & y || f[i ^ y] == INT_MAX || f[i ^ y] == INT_MIN) continue; if (d[x] == 1) { if (c[x] == 'p') f[i] = std::max(f[i], f[i ^ y] + a[j]); else f[i] = std::max(f[i], f[i ^ y]); } else { if (c[x] == 'p') f[i] = std::min(f[i], f[i ^ y] - a[j]); else f[i] = std::min(f[i], f[i ^ y]); } } } printf("%d", f[0]); fclose(stdin); fclose(stdout); return 0; }
D
官方做法是把l,v,r看成平面上的矩形。用线段树求出重叠数最多的部分。
E
仔细分析一下,很明显是维护一个下凸,用单调栈即可。