首页 > 其他分享 >[题解]P3966 [TJOI2013] 单词

[题解]P3966 [TJOI2013] 单词

时间:2024-08-12 20:17:53浏览次数:7  
标签:P3966 get int 题解 tr TJOI2013 ans fail define

P3966 [TJOI2013] 单词

用\(p[i]\)来表示经过节点\(i\)的字符串个数。

那么节点\(u\)的答案就是fail树上,以\(u\)为根的子树的\(p\)之和。

由于我们已经计算了\(p[i]\),所以字符串\(i\)作为模式串本身&模式串前缀的情况已经考虑了。还需考虑\(i\)作为模式串后缀的情况,而只有fail树上子树\(i\)的节点才有\(i\)这个后缀,所以累加即可。

点击查看代码
#include<bits/stdc++.h>
#define T 210
#define N 1000010
#define S 26
using namespace std;
int n,tr[N][S],fail[N],cnt,ans[N],pos[T],deg[N];
queue<int> q;
string s;
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;
		p=tr[p][c];
		ans[p]++;
	}
	pos[num]=p;
}
void get_fail(){
	for(int i=0;i<26;i++)
		if(tr[0][i]) q.push(tr[0][i]);
	while(!q.empty()){
		int u=q.front();
		q.pop();
		for(int i=0;i<26;i++){
			if(tr[u][i])
				fail[tr[u][i]]=tr[fail[u]][i],
				q.push(tr[u][i]),deg[fail[tr[u][i]]]++;
			else tr[u][i]=tr[fail[u]][i];
		}
	}
}
void topo(){
	for(int i=1;i<=cnt;i++) if(!deg[i]) q.push(i);
	while(!q.empty()){
		int t=q.front();
		q.pop();
		ans[fail[t]]+=ans[t],deg[fail[t]]--;
		if(!deg[fail[t]]) q.push(fail[t]);
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>s;
		ins(s,i);
	}
	get_fail();
	topo();
	for(int i=1;i<=n;i++)
		cout<<ans[pos[i]]<<"\n";
	return 0;
}

还有一种方法可以不用拓扑排序,就是用数组来模拟get_fail()中的队列,这样队头到队尾一定是BFS序,所以反过来,从队尾到队头一定是一个拓扑序,所以更新的时候不用拓扑排序,仅需用一个循环,从队尾遍历到队头,更新答案即可。

点击查看代码
#include<bits/stdc++.h>
#define T 210
#define N 1000010
#define S 26
using namespace std;
int n,tr[N][S],fail[N],cnt,ans[N],pos[T],q[N];
string s;
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;
		p=tr[p][c];
		ans[p]++;
	}
	pos[num]=p;
}
void get_fail(){
	int head=1,tail=0;
	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];
		}
	}
}
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>s;
		ins(s,i);
	}
	get_fail();
	for(int i=cnt;i>=1;i--) ans[fail[q[i]]]+=ans[q[i]];
	for(int i=1;i<=n;i++)
		cout<<ans[pos[i]]<<"\n";
	return 0;
}

标签:P3966,get,int,题解,tr,TJOI2013,ans,fail,define
From: https://www.cnblogs.com/Sinktank/p/18355554

相关文章

  • 【题解】 小狗
    题目描述【题目描述】小Q是个爱狗狂魔,他饲养了N(N<=2000)条中华田园犬狗和M(M<=2000)条秋田犬。并且给每条狗取了一个英文名字,例如:Sally,Sussan,Lysa等,为了方便起见,小Q登记时只会登记首字母,例如Sally、Sussan、Lysa只会登记为S、S、L。现在中华田园犬......
  • 题解:NOIP2023 天天爱打卡
    题解:NOIP2023天天爱打卡标签:线段树优化dp先考虑一个朴素的dp,\(f[i]\)表示前\(i\)天,第\(i\)天必打卡能得到的最大能量,有转移:\[f[i]=\max_{j=i-k+1}^{i}(val(j,i)-d\times(i-j+1)+\max_{p=1}^{j-2}f[p])\]\(val(j,i)\)表示第\(j\simi\)天完成的挑战.......
  • [题解]P2292 [HNOI2004] L 语言
    P2292[HNOI2004]L语言注:下文中,\(s[l\simr]\)表示截取字符串\(s\)的第\(l\)个字符到第\(r\)个字符。文字描述的字符串下标从\(1\)开始,但代码实现从\(0\)开始。我们建出AC自动机后,有一个比较暴力的思路。我么用\(f[i]\)表示待查找字符串\(t\)的长度为\(i\)前缀是否满足......
  • AtCoder ABC 366题解
    前言本文部分思路来自于网络,仅供参考。A-Election2题目大意给定两个市长候选人的票数,求结果是否已经确定。解题思路如果剩下的人全部投票给票少的人票少的人也不能赢,则结果就已经确定了。code#include<bits/stdc++.h>usingnamespacestd;intmain(){intn,t,......
  • ABC366D 题解
    第一眼是想写\(kd-tree\)的。然后发现这就是一道三维前缀和的板子题。三维前缀和要想学习三维前缀和,我们首先得了解前缀和的概念,并且学会一维、二维前缀和。什么是前缀和前缀和是容斥原理的典型应用。这种优化方式可以使求和操作的时间复杂度降低到\(O(1)\)(但是需要提前预......
  • 题解:AT_abc351_f [ABC351F] Double Sum
    关于某c人士强制偷袭代码导致AT号被封,\({\color{red}\mathrm{警钟敲碎}}\)。题意一个长\(n\)的数组\(a\),求所有顺序对中两元素之差的和。分析听说有大佬2min切掉。很明显,暴力过不去。考虑计算每个元素的贡献。设\(id\)为该元素之前所有比它小的元素个数,\(sum\)表示这些......
  • tensorboard_logger库无法导入的问题解决
    一、问题描述最近在学习深度学习时,从大神们那里copy的代码中有用到tensorboard_logger这个库的东西,所以很自然地就用condainstall或者pip去安装它,但是结果是:python开源库里面没有这东西。这就让我很苦恼,所以只能自己动手,丰衣足食了。 二、解决方法首先找到tensorboard_logge......
  • ABC366 G - XOR Neighbors 题解
    发现题目实质上就是让你构造一组\(a_{1,2,\dots,n}\),有一些限制,要求一些\(a\)异或起来是\(0\)。看到\(n\le60\),果断列异或方程组,用异或高斯消元。具体地,有\(n\)个方程组,\(a_{i,j}\)表示第\(i\)个方程中\(j\)的系数。对于每一个变量\(i\),要把\(j>i\)的方程中的第......
  • 【题解】P3356 火星探险问题
    \(\large\mathfrak{1st.\Preamble|}\)前言这都什么年代了网络流24题居然还能写题解!个人认为这篇题解讲的还是比较详细的。\(\large\mathfrak{2nd.\Solution|}\)题解看到题目的第一眼,我的反应是这样的:这不跟深海机器人问题差不多吗?Ctrl-CCtrl-V秒了。不过我还是讲讲怎......
  • ABC366D 题解
    Solution题意简述给你一个正整数\(N\)和\(N^3\)个非负整数,表示为\(A_{x,y,z}\)其中\(1\leqx,y,z\leqN\)。您将得到以下格式的\(Q\)个查询,必须按顺序处理。对于第\(i\)次查询\((1\leqi\leqQ)\),您将得到一个整数元组\((Lx_i,Rx_i,Ly_i,Ry_i,Lz_i,......