Hiho#1366 : 逆序单词(Trie树)

博主链接

题目链接

题意:

给你N个串,求出有多少对逆序串,即一个串逆序是另外一个串

题解:

每输入一个串将其插入trie树就判断下trie树中是否有他的逆序串,如果有就ans++

代码:

#include<stdio.h>
#include<bits/stdc++.h>
#define ll long long int
#define max_n 1000050
#define max_tot 500050
#define met(a) memset(a,0,sizeof(a))
#define fup(i,a,n,b) for(int i=a;i<n;i+=b)
#define fow(j,a,n,b) for(int j=a;j>0;j-=b)
#define MOD(x) (x)%mod
using namespace std;
const int maxn = 1e5 + 7;
struct Ac {
	struct state{  //节点状态
		int next[26];
		int fail, cnt;//指针fail 到这个节点有cnt个串结束
	}stable[max_tot];
	int size;  //当前AC自动机节点个数
	queue<int>q;
	void init() {  //初始化
		for (int i = 0; i < max_tot; i++) {
			met(stable[i].next);
			stable[i].fail = stable[i].cnt = 0;
		}
		size = 1;
		while (!q.empty())q.pop();
	}
	int ans = 0;
	void insert(char *s) {  //将模式串插入trie树
		int now = 0; //代表走到那个节点
		for (int i = 0;s[i]; i++) {
			char ch = s[i];  
			if (!stable[now].next[ch - 'a'])  //节点不存在该字母边,则新建一个
				stable[now].next[ch - 'a'] = size++;
			now = stable[now].next[ch - 'a'];
		}
		stable[now].cnt++;//结束位置++;
	}
	void build() {  //构造失配fail指针,要构造当前节点fail指针需先构造爸爸节点
		stable[0].fail = -1;
		q.push(0);
		while (!q.empty()) {
			int u = q.front();
			q.pop();
			for (int i = 0; i < 26; i++) {
				if (stable[u].next[i]) {  //如果有i这条边 枚举下他儿子
					if (u == 0)stable[stable[u].next[i]].fail = 0;
					else {
						int v = stable[u].fail;
						while (v != -1) {  //一直找它祖先的fail
							if (stable[v].next[i]) {  //如果他某个祖先有i这条边
								int a = stable[u].next[i];
								stable[a].fail = stable[v].next[i];
								break; 
							}
							v = stable[v].fail;
						}
						int a = stable[u].next[i];
						if (v == -1)stable[a].fail = 0;//如果没找到 ,就只能指向0
					}
					q.push(stable[u].next[i]);  //节点加进去
				}
			}
		}
	}
	int get(int u) {  //算所有祖先的和
		int res = 0;
		while (u) {
			res = res + stable[u].cnt;
			stable[u].cnt = 0;  //计算后不再计算,如果要计算不清零
			u = stable[u].fail;
		}
		return res;
	}
	int match(char *s) {   //匹配
		int res = 0, now = 0;
		for (int i = 0; s[i]; i++) {
			char ch = s[i];
			if (stable[now].next[ch - 'a'])  //如果当前状态太能找到后继节点,则走他
				now = stable[now].next[ch - 'a'];
			else {  //否则只能跳爸爸
				int p = stable[now].fail;
				while (p != -1 && stable[p].next[ch - 'a'] == 0)p = stable[p].fail;
				if (p == -1)now = 0;  //始终没找到,只能指根节点
				else now = stable[p].next[ch - 'a'];  //找到就跳对应地方
			}
			if (stable[now].cnt)res = res + get(now);
		}
		return res;
	}

	void check(char *s) {
		int now = 0;/
		int n = strlen(s);
		for (int i =n-1 ; i>=0; i--) {
			int ch = s[i];
			if (!stable[now].next[ch - 'a'])return;
			now=stable[now].next[ch - 'a'];
		}
		if (stable[now].cnt)ans++;
	}
}Ac;

char s[max_n];
int main(int argc, char *argv[]) {
	/*ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);*/
	int t,n;
	Ac.init();
	scanf("%d", &n);
	for (int i = 0; i < n; i++) {
		scanf("%s", s);
		Ac.check(s);
		Ac.insert(s);
	}
	printf("%d\n", Ac.ans);
	return 0;
}
全部评论

相关推荐

真tmd的恶心,1.面试开始先说我讲简历讲得不好,要怎样讲怎样讲,先讲背景,再讲技术,然后再讲提升多少多少,一顿说教。2.接着讲项目,我先把背景讲完,开始讲重点,面试官立即打断说讲一下重点,无语。3.接着聊到了项目的对比学习的正样本采样,说我正样本采样是错的,我解释了十几分钟,还是说我错的,我在上一家实习用这个方法能work,并经过市场的检验,并且是顶会论文的复现,再怎么不对也不可能是错的。4.面试官,说都没说面试结束就退出会议,把面试者晾在会议里面,丝毫不尊重面试者难受的点:1.一开始是讲得不好是欣然接受的,毕竟是学习。2.我按照面试官的要求,先讲背景,再讲技术。当我讲完背景再讲技术的时候(甚至已经开始蹦出了几个技术名词),凭什么打断我说讲重点,是不能听出人家重点开始了?这也能理解,每个人都有犯错,我也没放心上。3.我自己做过的项目,我了解得肯定比他多,他这样贬低我做过的项目,说我的工作是错误的,作为一个技术人员,我是完全不能接受的,因此我就和他解释,但无论怎么解释都说我错。凭什么,作为面试官自己不了解相关技术,别人用这个方式work,凭什么还认为这个方法是错的,不接受面试者的解释。4.这个无可厚非,作为面试官,不打招呼就退出会议,把面试者晾着,本身就是有问题。综上所述,我现在不觉得第一第二点也是我的问题,面试官有很大的问题,就是专门恶心人的,总结面试官说教,不尊重面试者,打击面试者,不接受好的面试者,技术一般的守旧固执分子。有这种人部门有这种人怎么发展啊。最后去查了一下,岗位关闭了。也有可能是招到人了来恶心人的,但是也很cs
牛客20646354...:招黑奴啊,算法工程师一天200?
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务