首页 > 其他分享 >[题解]UVA1127 Word Puzzles

[题解]UVA1127 Word Puzzles

时间:2024-08-19 16:05:48浏览次数:7  
标签:en int 题解 tt tr Puzzles UVA1127 fail void

UVA1127 Word Puzzles

我们对模式串建立AC自动机,然后就比较板子了,只需要把\(8\)个方向都跑一遍匹配就可以了。

时间复杂度是\(O(T\times 8nm)\)。

注意输入是大写字母。

点击查看代码
#include<bits/stdc++.h>
#define K 1010//模式串个数 & 矩阵长宽
#define N 1000010//节点个数(模式串总长)
#define C 26//字符集大小
using namespace std;
int tt,n,m,k;
int cnt,tr[N][C],fail[N],en[N],len[N];
int q[N],head,tail;
int ansx[K],ansy[K],ansd[K];
int dx[8]{-1,-1,0,1,1,1,0,-1},dy[8]{0,1,1,1,0,-1,-1,-1};
string s[K],t;
void clear(int x){
	memset(tr[x],0,sizeof tr[x]);
	fail[x]=en[x]=len[x]=0;
}
void ins(string s,int num){
	int p=0;
	for(char i:s){
		int c=i-'A';
		if(!tr[p][c]) tr[p][c]=++cnt,clear(cnt);
		p=tr[p][c];
	}
	en[p]=num,len[p]=s.size();
}
void get_fail(){
	head=0,tail=-1;
	for(int i=0;i<26;i++) if(tr[0][i]) q[++tail]=tr[0][i];
	while(head<=tail){
		int u=q[head++];
		for(int i=0;i<26;i++){
			if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q[++tail]=tr[u][i];
			else tr[u][i]=tr[fail[u]][i];
		}
	}
}
void query(int x,int y,int d){
	int p=0;
	while(x<n&&y<m&&x>=0&&y>=0){
		p=tr[p][s[x][y]-'A'];
		int xx=x-dx[d]*(len[p]-1),yy=y-dy[d]*(len[p]-1);//开始位置
		if(en[p]&&(xx<ansx[en[p]]||(xx==ansx[en[p]]&&yy<ansy[en[p]])))
			ansx[en[p]]=xx,ansy[en[p]]=yy,ansd[en[p]]=d;
		x+=dx[d],y+=dy[d];
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>tt;
	while(tt--){
		memset(ansx,127,sizeof ansx);
		memset(ansy,127,sizeof ansy);
		clear(0);
		cin>>n>>m>>k;
		for(int i=0;i<n;i++) cin>>s[i];
		for(int i=1;i<=k;i++){
			cin>>t;
			ins(t,i);
		}
		get_fail();
		for(int i=0;i<n;i++) for(int j=0;j<8;j++) query(i,0,j),query(i,m-1,j);
		for(int i=0;i<n;i++) for(int j=0;j<8;j++) query(0,i,j),query(n-1,i,j);
		for(int i=1;i<=k;i++)
			cout<<ansx[i]<<" "<<ansy[i]<<" "<<char(ansd[i]+'A')<<"\n";
		cout<<"\n";
	}
	return 0;
}

上面的写法是每匹配成功,就计算得到字符串的开始位置。

还有一种写法,就是反向建Trie,把模式串全部翻转再扔进去。这样匹配成功的位置直接就是字符串的开始位置了,效率会高不少(370ms => 200ms)。需要注意这样写的话,匹配成功时的方向和实际方向是相反的,需要反向一下。

点击查看代码
#include<bits/stdc++.h>
#define K 1010//模式串个数 & 矩阵长宽
#define N 1000010//节点个数(模式串总长)
#define C 26//字符集大小
using namespace std;
int tt,n,m,k;
int cnt,tr[N][C],fail[N],en[N];
int q[N],head,tail;
int ansx[K],ansy[K],ansd[K];
int dx[8]{-1,-1,0,1,1,1,0,-1},dy[8]{0,1,1,1,0,-1,-1,-1};
string s[K],t;
void clear(int x){
	memset(tr[x],0,sizeof tr[x]);
	fail[x]=en[x]=0;
}
void ins(string s,int num){
	int p=0,n=s.size();
	for(int i=n-1;i>=0;i--){
		int c=s[i]-'A';
		if(!tr[p][c]) tr[p][c]=++cnt,clear(cnt);
		p=tr[p][c];
	}
	en[p]=num;
}
void get_fail(){
	head=0,tail=-1;
	for(int i=0;i<26;i++) if(tr[0][i]) q[++tail]=tr[0][i];
	while(head<=tail){
		int u=q[head++];
		for(int i=0;i<26;i++){
			if(tr[u][i]) fail[tr[u][i]]=tr[fail[u]][i],q[++tail]=tr[u][i];
			else tr[u][i]=tr[fail[u]][i];
		}
	}
}
void query(int x,int y,int d){
	int p=0;
	while(x<n&&y<m&&x>=0&&y>=0){
		p=tr[p][s[x][y]-'A'];
		if(en[p]&&(x<ansx[en[p]]||(x==ansx[en[p]]&&y<ansy[en[p]])))
			ansx[en[p]]=x,ansy[en[p]]=y,ansd[en[p]]=(d+4)%8;//+4是因为Trie是倒着建的
		x+=dx[d],y+=dy[d];
	}
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(nullptr),cout.tie(nullptr);
	cin>>tt;
	while(tt--){
		memset(ansx,127,sizeof ansx);
		memset(ansy,127,sizeof ansy);
		clear(0);
		cin>>n>>m>>k;
		for(int i=0;i<n;i++) cin>>s[i];
		for(int i=1;i<=k;i++){
			cin>>t;
			ins(t,i);
		}
		get_fail();
		for(int i=0;i<n;i++) for(int j=0;j<8;j++) query(i,0,j),query(i,m-1,j);
		for(int i=0;i<n;i++) for(int j=0;j<8;j++) query(0,i,j),query(n-1,i,j);
		for(int i=1;i<=k;i++)
			cout<<ansx[i]<<" "<<ansy[i]<<" "<<char(ansd[i]+'A')<<"\n";
		cout<<"\n";
	}
	return 0;
}

标签:en,int,题解,tt,tr,Puzzles,UVA1127,fail,void
From: https://www.cnblogs.com/Sinktank/p/18367487

相关文章

  • el-table使用sortablejs推拽排序卡顿问题解决
    使用sortablejs拖拽el-table排序时,对于纯文本表格,正常使用即可,不会卡顿initSort(){consttbody=document.querySelector('.el-table__body-wrappertbody')const_this=thisSortable.create(tbody,{draggable:'.el-table__row',......
  • 【题解】Solution Set - NOIP2024集训Day10 树的直径、重⼼、中⼼
    【题解】SolutionSet-NOIP2024集训Day10树的直径、重⼼、中⼼https://www.becoder.com.cn/contest/5464「CF516D」DrazilandMorningExercise首先,我们可以换根求出所有点的\(f\)。然后不会了……思考一下,一条直径提供的到底时什么。实际上,一条直径上的点取到\(f\)......
  • Vue 项目报错Uncaught SyntaxError: Unexpected token < 刷新之后又可以继续访问问题解
    场景:页面打开不操作,前端项目代码更新重新部署后(比如Jenkins发布部署)页面不刷新,操作页面(点击打开弹窗、切换菜单等),页面没有反应,控制台报错 UncaughtSyntaxError:Unexpectedtoken<。这个问题偶现,只有在项目重新部署后会出现,页面刷新后就恢复正常 问题原因:在前端项目未更......
  • 题解:牛客周赛 Round 56(A-E)
    A面包店故事题面小镇上有一家面包店,面包以\(x\)元的价格出售,加\(y\)元可以多加几块培根。小歪带着\(n\)元来到了面包店,他想知道自己能不能买到加培根的面包?输入在一行上输入三个整数\(x,y,n\left(1\lex,y,n\le100\right)\)代表面包的价格、培根的价格和小歪带的......
  • P1540 [NOIP2010 提高组] 机器翻译 题解
    题目概括给定N个整数,和一个容量为M的“字典”,从头到尾依次翻译,每次翻译先看自家字典,没有的话再看别人的字典并存到自家字典,如果自家字典满了,当前单词的翻译会代替最早进入的。做题思路定义一个长度为M的字典数组,依次遍历N个数,每次翻译先检索字典数组,没有的话加入字典并......
  • 题解:P10844 [EGOI2024] Infinite Race / 无限赛跑
    题解:P10844[EGOI2024]InfiniteRace/无限赛跑有n个人在环形跑道上跑步,和q次超越别人或被别人超越,别人要么在Anika前面,要么在后面怎么说呢,建议降红由于只有重复超过一个人才肯定是跑过一圈的,所以一个数组就行了,每超过一次就打上标记,不然去掉标记。#include<bits/stdc......
  • 题解:AT_iroha2019_day1_f Head of The Dragon
    题目大意得知\(n\)和\(k\),求出\(n\)是否能分解出\(k\)个因数相乘,输出按字典序最小一种情况。步骤将\(n\)分解质因数。判断质因数个数是大于\(k\),否则输出\(-1\)。按照分解出来的质因数从小到大输出。代码#include<bits/stdc++.h>#defineintlonglongus......
  • Big Clique Everywhere 题解
    给个链接:BigCliqueEverywhere。先说一下团(clique)是什么,其实就是完全图。考虑什么情况下不满足题意。我们可以先建出补图,下面的东西都在补图中完成。我们首先给出结论:如果该图中有奇环(不是二分图),则条件不成立,否则成立。这里证明一下:如果存在奇环,则把点集设为这个奇环中的点,那......
  • 题解:AT_abc367_c [ABC367C] Enumerate Sequences
    大致题意让你按照字典序输出一些长\(n\)的序列,序列中的数字有范围,且序列和需要为\(k\)。分析直接深搜。搜索的时候对从第一个元素开始,每个元素从小到大枚举所有可能的值,这样就保证答案按照字典序升序排列。用一个vector存储序列,到达边界之后计算一遍和,判断是否满足条件,然......
  • 2024百度之星决赛部分题解(难度排序前六题)
    前言手速6题,可惜第四题磨了几个小时没磨出来,多做一题就金了,还是实力差了点,最后银牌前列。下面的题解是根据代码回忆大概的题意,主要是给出来赛时的参考代码A.状压题意:学校集训队总的有\(n\)个人,保证\(n\)是3的倍数,每个人有个人实力\(a_i\),每两个人之间有配合程度\(b_{i......