ZOJ 3817 Chinese Knot(牡丹江网络赛I题)

ZOJ 3817 Chinese Knot

题目链接

思路:万万没想到这题直接hash+暴力剪枝就可以了,把4个串正逆都hash出来,然后每次枚举起点去dfs记录下路径即可,剪枝为如果一旦有一点不匹配就不往后搜(这个很容易想到0 0)

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;

typedef unsigned long long ull;
const int N = 100005;
const ull seed = 123;

int t, n, m, st, en;
char str[N];
ull s[8][N], Hp[N], e[N];

int bo = 0;

struct Path {
	int u, dir, pos, end;
	Path() {}
	Path(int u, int dir, int pos, int end) {
		this->u = u;
		this->dir = dir;
		this->pos = pos;
		this->end = end;
	}
	void print() {
		if (dir == 0) {
			for (int i = pos; i <= end; i++) {
				if (bo) printf(" ");
				else bo = 1;
				printf("%d", u * n + i);
			}
		} else {
			for (int i = pos; i <= end; i++) {
				if (bo) printf(" ");
				else bo = 1;
				printf("%d", u * n + (n - i + 1));
			}
		}
	}
} ans[N];

int an;

bool dfs(int u, int dir, int pos, int len, ull hash) {
	ans[an++] = Path(u, dir, pos, n);
	if (len + n - pos + 1 >= m) {
		int tmpl = m - len;
		ull nh = hash + Hp[len] * (s[u * 2 + dir][pos] - s[u * 2 + dir][pos + tmpl] * Hp[tmpl]);
		if (nh == e[1]) {
			ans[an - 1].end = pos + tmpl - 1;
			return true;
		}
		an--;
		return false;
	}
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 2; j++) {
			if (i == u && (j^1) == dir) continue;
			int nl; ull nh;
			nl = len + n - pos + 1;
			nh = hash + Hp[len] * s[u * 2 + dir][pos];
			if (nh != e[1] - e[nl + 1] * Hp[nl]) continue;
			if (dfs(i, j, 1, nl, nh)) return true;
		}
	}
	an--;
	return false;
}

bool solve() {
	an = 0;
	for (int i = 0; i < 4; i++) {
		for (int j = 0; j < 2; j++) {
			for (int k = 1; k <= n; k++) {
				if (dfs(i, j, k, 0, 0)) return true;
			}
		}
	}
	return false;
}

int main() {
	Hp[0] = 1;
	for (int i = 1; i < N; i++)
		Hp[i] = Hp[i - 1] * seed;
	scanf("%d", &t);
	while (t--) {
		scanf("%d%d", &n, &m);
		for (int i = 0; i < 4; i++) {
			scanf("%s", str + 1);
			s[i * 2][n + 1] = 0;
			for (int j = n; j >= 1; j--)
				s[i * 2][j] = s[i * 2][j + 1] * seed + str[j];
			s[i * 2 + 1][n + 1] = 0;
			for (int j = n; j >= 1; j--)
				s[i * 2 + 1][j] = s[i * 2 + 1][j + 1] * seed + str[n - j + 1];
		}
		scanf("%s", str + 1);
		e[n + 1] = 0;
		for (int j = m; j >= 1; j--)
			e[j] = e[j + 1] * seed + str[j];
		if (!solve()) printf("No solution!\n");
		else {
			bo = 0;
			for (int i = 0; i < an; i++)
				ans[i].print();
			printf("\n");
		}
	}
	return 0;
}
时间: 2024-10-08 10:28:54

ZOJ 3817 Chinese Knot(牡丹江网络赛I题)的相关文章

ZOJ 3813 Alternating Sum (牡丹江网络赛E题)

ZOJ 3813 Alternating Sum 题目链接 赛后补题中,这题真心恶心爆了 先推下公式,发现是隔一个位置,长度从最长每次减2,这样累加起来的和,然后就可以利用线段树维护,记录4个值,奇数和,偶数和,奇数答案和,偶数答案和,这样pushup的时候,对应要乘系数其实就是加上左边奇(偶)和乘上右边长度,线段树处理完,还有个问题就是查询可能横跨很多个区间,这样一来就要把区间进行分段,分成3段,然后和上面一样的方法合并即可,注意中间一段很长,不能一一去合并,可以推成等差数列,利用前n项和去搞

ZOJ 3811 zoj 3811 Untrusted Patrol牡丹江网络赛C题

去年的比赛题目,今年才搞懂AC了===|| 1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cctype> 5 #include <cmath> 6 #include <algorithm> 7 #include <vector> 8 #include <queue> 9 #include <stack&g

【瞎搞】ZOJ 3818 Pretty Poem 牡丹江网络赛J题

第一种情况:ABABA. 先判断开头的A与结尾的A,得到A的长度,接着判断ABAB 中的AB与AB是否相同(ABAB的长度一定为偶数) 已经知道了A长度,AB的长度 接着判断下A 与B是否相同 第二种情况:ABABCAB-可先讲AB看成整体即DDCD 若存在一个D满足条件 可得到C的长度和位置再判断A-B是否相同A-C是否相同 B-C是否相同(暴力取A的长度咯) #include <stdio.h> #include <string.h> #include <stdlib.h

zoj 3817 Chinese Knot(hash+暴力)

题目链接:zoj 3817 Chinese Knot 题目大意:给出四个字符串,对应着同心结的四条边,现在给定一个目标串,可以从任意节点开始移动,问是否可以匹配目标串. 解题思路:用hash将四个字符串的正序和逆序处理出来,然后dfs枚举,每次保留起始位置和移动方向即可. #include <cstdio> #include <cstring> #include <vector> #include <algorithm> using namespace st

ZOJ 3812 We Need Medicine(牡丹江网络赛D题)

ZOJ 3812 We Need Medicine 题目链接 思路:dp[i][j][k]表示第i个物品,组成两个值为j和k的状态,这样会爆掉,所以状态需要转化一下 首先利用滚动数组,可以省去i这维,然后由于j最大记录到50,所以可以把状态表示成一个二进制数s,转化成dp[k] = s,表示组成k状态能组成s,这样空间复杂度就可以接受了,然后这题时限还可以,就这样去转移,然后记录下路径即可 代码: #include <cstdio> #include <cstring> #incl

ZOJ 3814 Sawtooth Puzzle(牡丹江网络赛F题)

ZOJ 3814 Sawtooth Puzzle 题目链接 记录状态广搜,把9个拼图都压缩成一个状态,然后去搜索,就是模拟的过程比较麻烦 代码: #include <cstdio> #include <cstring> #include <queue> #include <algorithm> #include <set> using namespace std; typedef unsigned long long ll; int t; int

ZOJ 3817 Chinese Knot

题意:给定4个长度为N的字符串( N <= 100000),然后构成一个“中国结”,给定目标串,问能否从某个节点出发走一遍得到目标串,其中不能连续通过3个中心节点,也就是从字符串一个端点转移到其他端点后必须沿着这条字符串走. 分析:对4个字符串正反两面和目标串建立相应hash函数,然后暴力枚举每一个位置出发就可以了,可以有正反两个方向的走法.中间注意一下细节差不多就可以了. 代码: 1 #include <bits/stdc++.h> 2 #pragma comment(linker,

ZOJ 2819 Average Score 牡丹江现场赛A题 水题/签到题

ZOJ 2819 Average Score Time Limit: 2 Sec  Memory Limit: 60 MB 题目连接 http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5373 Description Bob is a freshman in Marjar University. He is clever and diligent. However, he is not good at math, especia

ZOJ-3811 Untrusted Patrol DFS 2014牡丹江网络赛C题

n个点,m条双向边,k个传感器.其中有l个传感器记录到了第一次到达的时间顺序,求是否有可能检查了所有的顶点. 首先判断l,l<k一定是不行的.然后按照传感器的时间顺序dfs,先从第一个传感器位置搜索dfs搜到所有的到达传感器的位置结束,如果这个传感器被标记为可访问,则从这个传感器继续搜索下一层传感器,否则是不能满足时间顺序的.最后还要判断整个图的连通性,所有的顶点都要可以到达的. #include <iostream> #include <cstdio> #include &