[HNOI2019]校园旅行

人生第一道黑题祭

题解

本题偏重思维

判断回文可以考虑它的递归定义
只有一个字符的串是回文串。
只有两个字符的串,如果这两个字符相同,也是回文串;
如果 (S) 是回文串,那么在 (S) 的开头和末尾插入一个相同的字符,形成的新串也是回文串。

一个可以想到的方法是设 (f_{x,y}) 表示从 (x)(y) 可不可行
然后 ( ext{bfs}) 枚举边转移,(O(m^2),30pts)

正解是减少边
分别考虑 (0->0,1->1,0->1) 三种边形成的连通块
发现它们都满足
1.如果连通块是二分图(不存在奇环),经过偶环并不会对串的长度的奇偶性造成改变,再加上允许一条边可以走多次,因此没有必要保留环,只需保留这个连通块的一个生成树即可。
2.如果连通块不是二分图(存在奇环),经过奇环会影响串长度的奇偶性,为了方便处理,我们仍然只保留这个连通块的生成树,并在这个连通块的其中一个点上加一个自环(从而留下改变奇偶性的机会)。

以此只保留这些边
可以证明剩下边不超过 (2n-2) 条(别问我)
然后就没了

(Code)

#include<cstdio>
#include<cmath>
#include<queue>
using namespace std;

const int N = 5005, M = 500005;
int n, m, q, w[N], f[N][N];
char str[N];

inline void read(int &x)
{
	x = 0; int f = 1; char ch = getchar();
	while (ch < '0' || ch > '9') f = (ch == '-' ? -1 : f), ch = getchar();
	while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
	x *= f;
}

struct node{int x, y;};
queue<node> Q;

int h[N], H[N], X[M], Y[M];
struct edge{int to, nxt;}E[M << 1], e[M << 1];
inline void addE(int x, int y)
{
	static int totE = 0;
	E[++totE] = edge{y, H[x]}, H[x] = totE;
}
inline void add(int x, int y)
{
	static int tot = 0;
	e[++tot] = edge{y, h[x]}, h[x] = tot;
}

int bz1[N], col[N];
void color(int x, int c)
{
	col[x] = c;
	for(register int i = H[x]; i; i = E[i].nxt)
	{
		int v = E[i].to;
		if (!col[v]) color(v, -c);
		else if (col[x] == col[v]) bz1[abs(c)] = 1;
	}
}

int fa[N][2];
inline int find(int x, int y){return (fa[x][y] == x ? x : fa[x][y] = find(fa[x][y], y));}

int bz2[N];
inline void build()
{
	for(register int i = 1; i <= n; i++)
	if (!col[i]) color(i, i);
	for(register int i = 1; i <= m; i++)
	{
		int x = X[i], y = Y[i];
		if (w[x] ^ w[y])
		{
			int tx = find(x, 1), ty = find(y, 1);
			if (tx == ty) continue;
			fa[tx][1] = fa[ty][1], add(x, y), add(y, x);
		}
		else{
			int tx = find(x, 0), ty = find(y, 0);
			if (tx == ty) continue;
			fa[tx][0] = fa[ty][0], add(x, y), add(y, x), f[x][y] = f[y][x] = 1, Q.push(node{x, y});
		}
	}
	for(register int i = 1; i <= n; i++)
	if (bz1[abs(col[i])] && !bz2[abs(col[i])]) add(abs(col[i]), abs(col[i])), bz2[abs(col[i])] = 1;
}

inline void bfs()
{
	node now;
	while (!Q.empty())
	{
		now = Q.front(), Q.pop();
		for(register int i = h[now.x]; i; i = e[i].nxt)
			for(register int j = h[now.y]; j; j = e[j].nxt)
			{
				if (w[e[i].to] ^ w[e[j].to] || f[e[i].to][e[j].to]) continue;
				f[e[i].to][e[j].to] = f[e[j].to][e[i].to] = 1, Q.push(node{e[i].to, e[j].to});
			}
	}
}

int main()
{
	read(n), read(m), read(q), scanf("%s", str + 1);
	for(register int i = 1; i <= n; i++) w[i] = str[i] - '0', f[i][i] = 1, fa[i][0] = fa[i][1] = i, Q.push(node{i, i});
	int x, y;
	for(register int i = 1; i <= m; i++) 
	{
		read(x), read(y), X[i] = x, Y[i] = y;
		if (w[x] == w[y]) addE(x, y), addE(y, x);
	}
	build(), bfs();
	for(register int i = 1; i <= q; i++)
	{
		read(x), read(y);
		if (f[x][y] || f[y][x]) printf("YES
");
		else printf("NO
");
	}
}
原文地址:https://www.cnblogs.com/leiyuanze/p/14341983.html