人生第一道黑题祭
题解
本题偏重思维
判断回文可以考虑它的递归定义
只有一个字符的串是回文串。
只有两个字符的串,如果这两个字符相同,也是回文串;
如果 (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
");
}
}