第一题:明显先处理出最终序列,然后用线段树求解。处理最终序列可以用二分加树状数组(时间复杂度log2n, 用平衡树也可以搞。。。)。
/* * Problem: TJOI2013-day2-Sequence * 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; int getInt() { static char ch, f; static int ret; f = 1; while (ch = getchar(), ch < '0' || ch > '9') if (ch == '-') f = 0; ret = ch - '0'; while (ch = getchar(), ch >= '0' && ch <= '9') ret = (ret << 1) + (ret << 3) + ch - '0'; return f ? ret : -ret; } int n; int s[MAXN]; void modify(int x, int y) { static int i; for (i = x; i <= n; i += i & -i) s[i] += y; } int query(int x) { static int i, ret; ret = 0; for (i = x; i >= 1; i -= i & -i) ret += s[i]; return ret; } struct SegTree { int v; SegTree *l, *r; } *root; void build(SegTree *&p, int l, int r) { p = new SegTree(); p->v = 0; p->l = p->r = NULL; if (l == r) return; build(p->l, l, (l + r) >> 1); build(p->r, ((l + r) >> 1) + 1, r); } void modify(SegTree *p, int l, int r, int x, int y) { if (l == r) { p->v = y; return; } if (x <= (l + r) >> 1) modify(p->l, l, (l + r) >> 1, x, y); else modify(p->r, ((l + r) >> 1) + 1, r, x, y); p->v = std::max(p->l->v, p->r->v); } int query(SegTree *p, int l, int r, int x, int y) { if (l == x && y == r) return p->v; if (y <= (l + r) >> 1) return query(p->l, l, (l + r) >> 1, x, y); else if (x > (l + r) >> 1) return query(p->r, ((l + r) >> 1) + 1, r, x, y); return std::max(query(p->l, l, (l + r) >> 1, x, (l + r) >> 1), query(p->r, ((l + r) >> 1) + 1, r, ((l + r) >> 1) + 1, y)); } int main(/*int argc, char **argv*/) { int i, j, mid, l, r, x[MAXN], a[MAXN], ans; char v[MAXN]; freopen("sequence.in", "r", stdin); freopen("sequence.out", "w", stdout); n = getInt(); for (i = 1; i <= n; ++i) x[i] = getInt(); memset(v, 0, sizeof v); for (i = n; i >= 1; --i) { l = 1; r = n; while (l <= r) { mid = (l + r) >> 1; j = mid - query(mid); if (j == x[i] + 1) { if (!v[mid]) { v[a[i] = mid] = 1; modify(mid, 1); break; } else r = mid - 1; continue; } if (j > x[i] + 1) r = mid - 1; else l = mid + 1; } } build(root, 1, n); ans = 0; for (i = 1; i <= n; ++i) { j = query(root, 1, n, 1, a[i]); modify(root, 1, n, a[i], j + 1); if (ans < j + 1) ans = j + 1; printf("%d ", ans); } fclose(stdin); fclose(stdout); return 0; }
第二题:仔细分析可以发现应该按照a + b递增的顺序贪心出井,然后dp,f[i][j]代表前i个逃离了j个的剩余最大高度。
/* * Problem: Dwarf * 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 = 2222; int n, f[MAXN]; struct Data { int a, b; } c[MAXN]; bool cmpa(Data a, Data b) { return a.a + a.b < b.a + b.b; } int main(/*int argc, char **argv*/) { int i, j, h; freopen("dwarf.in", "r", stdin); freopen("dwarf.out", "w", stdout); scanf("%d", &n); for (i = 1; i <= n; ++i) scanf("%d%d", &c[i].a, &c[i].b); scanf("%d", &h); std::sort(c + 1, c + n + 1, cmpa); for (i = 1; i <= n; ++i) f[0] += c[i].a; for (i = 1; i <= n; ++i) f[i] = INT_MIN; for (i = 1; i <= n; ++i) for (j = i; j >= 1; --j) if (f[j - 1] != INT_MIN && f[j - 1] + c[i].b >= h && f[j] < f[j - 1] - c[i].a) f[j] = f[j - 1] - c[i].a; for (i = n; i >= 0; --i) if (f[i] >= 0) break; printf("%d", i); fclose(stdin); fclose(stdout); return 0; }
第三题:好吧,很明显二分图独立集(好像是好经典的题目啊!,据说匈牙利会被卡爆,我在BZOJ上交的。。。)
/* * Problem: TJOI2013-day2-Attack * 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 = 222; const int dx[8] = {1, 1, -1, -1, 2, 2, -2, -2}; const int dy[8] = {2, -2, 2, -2, 1, -1, 1, -1}; int n, mat[MAXN * MAXN]; bool used[MAXN * MAXN]; class Edge { public: int v; Edge *next; Edge() {} ~Edge() {} Edge(int V, Edge *ne) : v(V), next(ne) {} } *g[MAXN * MAXN]; void add(int x, int y) { g[x] = new Edge(y, g[x]); } bool find(int x) { for (Edge *e = g[x]; e; e = e->next) if (!used[e->v]) { used[e->v] = 1; if (!mat[e->v] || find(mat[e->v])) { mat[e->v] = x; return 1; } } return 0; } int main(/*int argc, char **argv*/) { int i, j, k, x, y, ans, sum; char s[MAXN][MAXN]; freopen("attack.in", "r", stdin); freopen("attack.out", "w", stdout); scanf("%d", &n); for (i = 1; i <= n; ++i) scanf(" %s", s[i] + 1); sum = 0; for (i = 1; i <= n; ++i) for (j = 1; j <= n; ++j) { if (s[i][j] == '1') continue; ++sum; if ((i + j) & 1) for (k = 0; k < 8; ++k) { x = i + dx[k]; y = j + dy[k]; if (x < 1 || x > n || y < 1 || y > n || s[x][y] == '1') continue; add((i - 1) * n + j, (x - 1) * n + y); } } ans = 0; memset(mat, 0, sizeof mat); for (i = 1; i <= n; ++i) for (j = 1; j <= n; ++j) if (s[i][j] == '0' && (i + j) & 1) { memset(used, 0, sizeof used); if (find((i - 1) * n + j)) ++ans; } printf("%d ", sum - ans); fclose(stdin); fclose(stdout); return 0; }