首页 > 其他分享 >P4770 [NOI 2018] 你的名字

P4770 [NOI 2018] 你的名字

时间:2023-02-02 23:12:24浏览次数:40  
标签:NOI P4770 int len st fa maxn 2018 cur

因为做的题太少所以不放在 SAM 集合里了捏,有时间(可能没时间) 会补一个集合。

题意:给 \(S\) 串和 \(T\) 串,和 \(l_i,r_i\) ,求 \(T\) 中有多少子串和 \(S[l_i,r_i]\) 中的任意一个子串不同。多组询问,\(\sum|T|\leq 10^5\)

考虑如果没有 \(l_i,r_i\) 的限制该怎么做。可以先对 \(S\) 建 SAM,然后用 \(T\) 在 SAM 上跑匹配。求出 \(c_i\) 表示 \(T[1,i]\) 中在 \(S\) 中能匹配的最长后缀。\(i-c_i+1\sim i\) 到 \(i\) 这段的都不行了。

这样看似可以,实际错误。因为没有考虑到 \(T\) 中的重复子串。

考虑这一点就是对 \(T\) 建出 SAM,对于每一个位置,都在 \(T\) 的 SAM 里找到对应节点,就是每一个位置所在的状态都要被记录上。然后在 T 的 SAM 上遍历每一个状态。这个状态里的 \(len_i-\max{(len_{fa},c_{pos})}\) 就是能造成的贡献。这个状态本身能贡献的就是 len 减掉 fa 的 len。而如果被叉掉的长度在这个状态表达的范围内,也要减掉比它小的贡献。

这是没有 l 和 r 询问的。

而如果有的话,就是个套路。用可持久化线段树合并,找到每一个点对应的 endpos 集合。集合里如果有当前查询区间 \(l-len+1\sim r\) 的endpos就可以转移。len的含义是当前 \(T\) 在 \(S\) 中匹配的最大后缀长度。然后就像上面一样做就行。

其实想明白之前挺煎熬的,想明白就挺简单的。

/*
     />  フ   
     |  _  _|	
     /`ミ _x 彡	
     /      |	
    /  ヽ   /	
 / ̄|   | | |	
 | ( ̄ヽ__ヽ_)_)	
 \二つ
*/
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=4000020;
char S[maxn],T[maxn];
int n,m;
int rt[maxn];
namespace SGT
{
	int lson[maxn*10],rson[maxn*10],tot; 
	void update(int l,int r,int x,int &p)
	{
		if(!p) p=++tot; 
		if(l==r) return;
		int mid=(l+r)>>1;
		if(x<=mid) update(l,mid,x,lson[p]);
		else update(mid+1,r,x,rson[p]);
	}
	int merge(int x,int y)
	{
		if(!x||!y) return x+y;
		int rt=++tot;
		lson[rt]=merge(lson[x],lson[y]);
		rson[rt]=merge(rson[x],rson[y]);
		return rt;
	}
	int query(int l,int r,int x,int y,int p)
	{
		if(l>r||!p||x>y) return 0;
		if(x<=l&&y>=r) return 1;
		int mid=(l+r)>>1;int ret=0;
		if(x<=mid) ret+=query(l,mid,x,y,lson[p]);
		if(y>mid) ret+=query(mid+1,r,x,y,rson[p]);
		return ret;
	}
}
int pos[maxn];
struct SAM
{
	struct node
	{
		int fa,len,tag;
		map<char,int> nxt; 
	}st[maxn];
	int sz,lst;
	void add(char c,int idx)
	{
		int cur=++sz; pos[idx]=cur; st[cur].len=st[lst].len+1; 
        st[cur].tag=st[cur].len;
		if(idx) SGT::update(1,n,idx,rt[cur]);
		int p=lst;
		while(p!=-1&&!st[p].nxt.count(c)) st[p].nxt[c]=cur,p=st[p].fa;
		if(p==-1)
			st[cur].fa=1;
		else
		{
			int q=st[p].nxt[c];
			if(st[q].len==st[p].len+1) st[cur].fa=q;
			else
			{
				int clone=++sz;
				st[clone].len=st[p].len+1; 
				st[clone].nxt=st[q].nxt; st[clone].fa=st[q].fa;
                st[clone].tag=st[q].tag;
				while(p!=-1&&st[p].nxt[c]==q) st[p].nxt[c]=clone,p=st[p].fa;
				st[q].fa=st[cur].fa=clone;
			}
		}
		lst=cur;
	}
	void clear()
	{
		for(int i=1;i<=sz;i++) st[i].fa=st[i].len=0,st[i].nxt.clear();
		sz=1; lst=1;
		st[1].len=0; st[1].fa=-1;
	}
}Ssam,Tsam;
int to[maxn],nxt[maxn],head[maxn],num;
void add(int x,int y){num++;to[num]=y;nxt[num]=head[x];head[x]=num;} 
void dfs(int p)
{
	for(int i=head[p];i;i=nxt[i]) 
		dfs(to[i]), rt[p]=SGT::merge(rt[to[i]],rt[p]);
}
int chk[maxn];
void match()
{
	int L,R;scanf("%d%d",&L,&R);
	int p=1; int ls=0;
	for(int i=1;i<=m;i++)
	{
		Tsam.add(T[i],0);
		while(1)
		{
			if(p!=-1&&Ssam.st[p].nxt.count(T[i])&&SGT::query(1,n,L+ls,R,rt[Ssam.st[p].nxt[T[i]]])) 
			{
				ls++; p=Ssam.st[p].nxt[T[i]]; 
				break;
			}
			if(!ls) break; ls--;
			if(ls==Ssam.st[Ssam.st[p].fa].len) p=Ssam.st[p].fa;
		}  
		chk[i]=ls;
	}
	ll ans=0;
	for(int i=2;i<=Tsam.sz;i++) 
        ans+=max(0,Tsam.st[i].len-max(Tsam.st[Tsam.st[i].fa].len,chk[Tsam.st[i].tag]));
	printf("%lld\n",ans);
}
int main()
{
	//freopen("name.in","r",stdin);
	//freopen("name.out","w",stdout);
	scanf("%s",S+1); n=strlen(S+1);
	Ssam.clear(); 
	for(int i=1;i<=n;i++) 
		Ssam.add(S[i],i);
	for(int i=2;i<=Ssam.sz;i++) add(Ssam.st[i].fa,i);
	dfs(1);
	int test; scanf("%d",&test);
	while(test--)
	{
		scanf("%s",T+1); m=strlen(T+1);
		Tsam.clear();
		match();
	}
}

标签:NOI,P4770,int,len,st,fa,maxn,2018,cur
From: https://www.cnblogs.com/cc0000/p/17087703.html

相关文章

  • 新魔百和 M301H 南传JL 201803款
     https://histb.com/厂商机型:新魔百和M301H南传JL201803款CPU芯片:hi3798mv300支持64位reg名称:mv3dmw运存大小:1G存储类型及大小:EMMC8G推荐最佳刷机方式:短接U盘......
  • noi 2.1基本算法之枚举
    7647:余数相同问题1.描述已知三个正整数a,b,c。现有一个大于1的整数x,将其作为除数分别除a,b,c,得到的余数相同。请问满足上述条件的x的最小值是多少?数据保证x有解。2.输......
  • 2018-08-31知识小结
    安装一个本地包pacman-U/path/to/package/package_name-version.pkg.tar.xz对于网络安全来讲,似乎构造数据包是一种必要的技术手段相对于nmap来说,zenmap更适合......
  • 2018-08-29知识小结
    CIDR一个ISP准备把一些C类网络分配给各个用户群,目前已经分配了三个C类网段给用户,如果没有实施CIDR技术。ISP的路由器的路由表中会有三条下连网段的路由条目,并且会把它通告......
  • P1045 [NOIP2003 普及组] 麦森数——快速幂
    [NOIP2003普及组]麦森数题目描述形如\(2^{P}-1\)的素数称为麦森数,这时\(P\)一定也是个素数。但反过来不一定,即如果\(P\)是个素数,\(2^{P}-1\)不一定也是素数。到......
  • NOI2022冒泡排序
    首先考虑A性质的点。区间最小值为\(1\)的限制等价于要求区间所有值为\(1\)。另外一种限制等价于区间不全为\(1\)。把一定是\(1\)的做一个区间覆盖。其他部分暂且......
  • [APIO2018] 铁人两项
    题意:问有多少点(x,y,z)满足从x出发经过y到z。且点不能重复经过。题解:前置芝士1:点双有个性质:两点之间简单路径的并集刚好等于这个点双(证明用网络流模型)等价不同点uv......
  • 【题解】[LNOI2022] 盒
    题目分析:我们可以对每一条边单独计算贡献,这样会发现贡献很好算:\[ans=\sum_{i=0}^{n-1}w_i\sum_{j=0}^S|j-s_i|\binom{i+j-1}{i-1}\binom{S-j+n-i-1}{n......
  • 关于NOI2010“超级钢琴”的反思
    [NOI2010]超级钢琴题目描述小Z是一个小有名气的钢琴家,最近C博士送给了小Z一架超级钢琴,小Z希望能够用这架钢琴创作出世界上最美妙的音乐。这架超级钢琴可以弹奏......
  • P1020 [NOIP1999 普及组] 导弹拦截
    [NOIP1999普及组]导弹拦截题目描述某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以......