• [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
    ");
    	}
    }
    
  • 相关阅读:
    笔试:一个逻辑题
    jmeter,学这些重点就可以了
    性能测试:通过一个案例(等待锁超时)告诉你,性能到底要不要熟悉业务逻辑?
    源码解读:webdriver client的原理 (面试自动化:如果你认为知道18种定位方式就算会自动化,那就太low了)
    测试必备:jmeter测试http协议接口的各种传参方式
    Vue笔记:封装 axios 为插件使用
    Vue笔记:使用 axios 发送请求
    Tomcat笔记:Tomcat的执行流程解析
    Git笔记:Git介绍和常用命令汇总
    Spring Boot使用Shiro实现登录授权认证
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/14341983.html
Copyright © 2020-2023  润新知