码迷,mamicode.com
首页 > 其他好文 > 详细

20180810 提高 练习赛

时间:2018-08-10 23:27:38      阅读:366      评论:0      收藏:0      [点我收藏+]

标签:复杂   inline   res   等于   直接   mem   lin   rate   turn   

题目目录,题意什么的先鸽着

第一题 题解

傻逼排序题,将点按 $x$ 轴排序,然后取前六个点即可。

代码:

#include <bits/stdc++.h>
using namespace std;

inline int rd(){int ch,ret,nag=0;while(!isdigit(ch=getchar()))nag=ch==‘-‘;ret=ch-‘0‘;while(isdigit(ch=getchar()))ret=ret*10+ch-‘0‘;return nag?-ret:ret;}

struct Point {
	int x, y, id;
	inline bool operator< (const Point & res) const {
		return x == res.x ? y < res.y : x < res.x;
	}
	inline void rd(int i) {
		x = ::rd(); y = ::rd(); id = i;
	}
} a[100005];

int main() {
	int n = rd();
	for (int i = 0; i < n; i++) a[i].rd(i);
	sort(a, a+n);
	for (int i = 0; i < 6; i++) printf(i == 5 ? "%d" : "%d ", a[i].id+1);
	puts("");
	return 0;
}

第二题 题解

记忆化搜索点 $(x,y)$ 能到的最远路径

如果遇到相同的值直接设成 inf

然后询问判断 $l$ 是不是小于等于最远路径

代码

#include <bits/stdc++.h>
using namespace std;

int n, m, q, a[1005][1005], dp[1005][1005];
bool vis[1005][1005];

const int INF = 0x3f3f3f3f;

const int dx[] = {1, -1, 0, 0};
const int dy[] = {0, 0, 1, -1};

int dfs(int x, int y) {
	if (vis[x][y]) return dp[x][y];
	int ans = 0;
	for (int i=0; i<4; i++) {
		int nx = dx[i] + x, ny = dy[i] + y;
		if (nx < 1 || ny < 1 || nx > n || ny > m) continue;
		if (a[nx][ny] < a[x][y]) continue;
		if (a[nx][ny] == a[x][y]) { ans = INF; break; }
		ans = max(ans, dfs(nx, ny) + 1);
	}
	return dp[x][y] = ans;
}

int main() {
	// freopen("nagame.in", "r",stdin);
	// freopen("nagame.out", "w",stdout);
	scanf("%d%d", &n,&m);
	for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) scanf("%d", &a[i][j]);
	for (int i=1; i<=n; i++) for (int j=1; j<=m; j++) if (!vis[i][j]) dfs(i, j);
	scanf("%d", &q);
	while(q--) {
		int x, y, z; scanf("%d%d%d", &x, &y, &z);
		printf("%s\n", dp[x][y]>=z ? "= =" : "> <");
	}
	return 0;
}

第三题 题解

首先考虑一颗树怎么做。当然是树形dp。

然后我们考虑加了一些附件边后怎么做。先求一颗生成树,然后对于剩下的几条边,暴力枚举它两个点的情况:

  1. 一白一白
  2. 一白一黑
  3. 一黑一白

发现如果第一个点是白点,那第二个点不用管。

所以枚举的时间复杂度是 $\mathcal O(2^(m-n+1))$,最多 $64$ 。

调试记录

  • 没有判断一个点有两种限制的情况。

代码

#include <bits/stdc++.h>
using namespace std;

inline int rd(){int ch,ret,nag=0;while(!isdigit(ch=getchar()))nag=ch==‘-‘;ret=ch-‘0‘;while(isdigit(ch=getchar()))ret=ret*10+ch-‘0‘;return nag?-ret:ret;}

int n, m, e=0, ans1=0, ans0=0, hed[100005], use[100005], spn[100005];
struct edge {
	int to, nxt;
} edges[200005];
struct rawedge {
	int x, y;
	inline void rd() { x = ::rd(); y = ::rd(); }
} A[200005];
struct UnionSet {
	int fa[100005];
	void I(int n) {
		for (int i=1; i<=n; i++) fa[i] = i;
	}
	int f(int x) {
		return fa[x] = (x == fa[x] ? x : f(fa[x]));
	}
	void u(int x, int y) {
		x = f(x), y = f(y);
		if (x == y) return;
		fa[x] = y;
	}
} S;
const int P = 1000000007;
int dp[100005][2], color[100005];
vector<int> U;

inline void addedge(int x, int y) {
	edges[e] = (edge){y, hed[x]};
	hed[x] = e++;
}
void findGenerateTree() {
	S.I(n);
	for (int i=1; i<=m; i++) if (S.f(A[i].x) != S.f(A[i].y)) {
		use[i] = 1, S.u(A[i].x, A[i].y), addedge(A[i].x, A[i].y), addedge(A[i].y, A[i].x);
	}
}
void dfs(int x, int fa) {
	dp[x][0] = dp[x][1] = 1;
	for (int e=hed[x]; e!=-1; e=edges[e].nxt) {
		int y = edges[e].to;
		if (y != fa) {
			dfs(y, x);
			dp[x][0] = 1ll * dp[x][0] * (dp[y][0] + dp[y][1]) % P;
			dp[x][1] = 1ll * dp[x][1] * dp[y][0] % P;
		}
	}
	if (spn[x] == 1) dp[x][1] = 0;
	else if (spn[x] == 2) dp[x][0] = 0;
}

int main() {
	// freopen("akekure.in", "r",stdin);
	// freopen("akekure.out", "w",stdout);
	n = rd(); m = rd();
	for (int i=1; i<=n; i++) hed[i] = -1;
	for (int i=1; i<=m; i++) A[i].rd();
	findGenerateTree();
	int ans = 0;
	for (int i=1; i<=m; i++) if (!use[i]) U.push_back(i);
	assert(U.size() == (m - n + 1));
	for (int i=0; i<(1 << (m - n + 1)); i++) {
		memset(spn, 0, sizeof(spn));
		bool fail = 0;
		for (int j=0; j<U.size(); j++) if (i & (1 << j)) {
			if (spn[A[U[j]].x] > 1) { fail = 1; break; }
			spn[A[U[j]].x] = 1;
		} else {
			if (spn[A[U[j]].x] == 1 || spn[A[U[j]].y] > 1) { fail = 1; break; }
			spn[A[U[j]].x] = 2;
			spn[A[U[j]].y] = 1;
		}
		if (fail) continue;
		dfs(1, 0);
		(ans += (dp[1][0] + dp[1][1]) % P) %= P;
	}
	printf("%d\n", ans);
	return 0;
}

  

20180810 提高 练习赛

标签:复杂   inline   res   等于   直接   mem   lin   rate   turn   

原文地址:https://www.cnblogs.com/mchmch/p/contest-20180810.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!