TJOI2013 DAY2

第一题:明显先处理出最终序列,然后用线段树求解。处理最终序列可以用二分加树状数组(时间复杂度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\n", 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\n", sum - ans);

	

	fclose(stdin);

	fclose(stdout);

	return 0;

}

 

你可能感兴趣的:(a)