TJOI2013 DAY2

第一题:明显先处理出最终序列,然后用线段树求解。处理最终序列可以用二分加树状数组(时间复杂度log2n, 用平衡树也可以搞。。。)。

/* 
 * Problem: TJOI2013-day2-Sequence
 * Author: Shun Yao
 */

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//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 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

//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;
}

 

你可能感兴趣的:(TJOI2013 DAY2)