首页 > 其他分享 >SPOJ Substrings 题解

SPOJ Substrings 题解

时间:2023-07-05 11:13:32浏览次数:36  
标签:题解 LL Substrings len 主链 SPOJ text now 节点

\(\text {SAM}\) 入门好题。

首先我们需要知道几个关于 \(\text{SAM}\) 的结论。

结论 1:题目中的 \(f(x)\) 单调下降。

显然,对于长度为 \(x\) 的子串,其必存在一个 \(x-1\) 的后缀,这个后缀的 \(\text {endpos}\) 集合肯定包含子串的 \(\text {endpos}\) 集合,所以必有 \(f(x-1)\leq f(x)\)。

结论 2:两个 \(\text {endpos}\) 集合要么是包含关系,要么是非交的,且取决于一个字符串是否是另一个字符串的后缀。

如果字符串 \(u\) 包含 \(v\),则 \(u\) 可匹配的位置 \(v\) 一定可以匹配。

否则,两者结尾不同有字符,故对于 \(u\) 可以匹配的每一个终点\(v\) 都不可以匹配。

结论 3:一个节点有一个终点当且仅当它的子树包含这个终点对应的主链的节点,一个子串在字符串中的出现次数为其子树中主链的节点的数量。

在这里,主链表示字符串前缀所在的终点等价类所代表的节点。

每个终点都有一个对应的主链的节点。

必要性:如果这个节点包含这个终点,根据结论 2,其必然包含主链上节点的 \(\text {endpos}\) 集合,故包含这个节点。

充分性:如果这个节点包含这个终点,但是不包含主链上的对应节点,则两者集合有交,与结论 2 矛盾,所以如果这个节点包含这个终点则必然包含主链上的对应节点。


那么知道了这些结论,我们该怎么做题呢?

发现了没有,对于一个终点等价类的子串,它们显然是有共同的出现次数的,而这一次数可以利用结论 4 求出。

所以我们考虑用一个拓扑来做一个树形 DP,求出之后,我们在节点的 \(\text {len}\) 对应的位置打标记记录答案,求一个后缀最大值即可。

为什么可以直接后缀最大值呢?参见结论 1。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=1e6+5;
struct node
{
	LL len,fa,num,du;
	map<char,LL>nxt;
}t[N];
LL n,a[N],lst,sz,f[N];
char c[N];
queue<LL>q;
void ins(char x)
{
	LL now=++sz;
	t[now].len=t[lst].len+1;
	t[now].num=1;
	LL p=lst;
	lst=now;
	while(p!=-1&&!t[p].nxt.count(x))
	{
		t[p].nxt[x]=now;
		p=t[p].fa;
	}
	if(p==-1)return;
	LL q=t[p].nxt[x];
	if(t[p].len+1==t[q].len)
	{
		t[now].fa=q;
		return;
	}
	LL cl=++sz;
	t[cl]=t[q],t[cl].num=0,t[cl].len=t[p].len+1;
	while(p!=-1&&t[p].nxt[x]==q)
	{
		t[p].nxt[x]=cl; 
		p=t[p].fa;
	}
	t[q].fa=t[now].fa=cl;
}
vector<char>v;
int main()
{
	t[0].fa=-1;
	scanf("%s",c+1);
	n=strlen(c+1);
	for(int i=1;i<=n;i++)ins(c[i]);
	for(int i=1;i<=sz;i++)
	{
		t[t[i].fa].du++;
	}
	for(int i=1;i<=sz;i++)
	{
		if(!t[i].du)q.push(i);
	}
	while(!q.empty())
	{
		LL k=q.front();
		q.pop();
		t[t[k].fa].num+=t[k].num;
		t[t[k].fa].du--;
		if(!t[t[k].fa].du)
		{
			q.push(t[k].fa);
		}
	}
	for(int i=1;i<=sz;i++)
	{
		f[t[i].len]=max(f[t[i].len],t[i].num);
	}
	for(int i=n-1;i>=1;i--)
	{
		f[i]=max(f[i],f[i+1]);
	}
	for(int i=1;i<=n;i++)
	{
		printf("%lld\n",f[i]);
	}
	return 0;
}

标签:题解,LL,Substrings,len,主链,SPOJ,text,now,节点
From: https://www.cnblogs.com/dengduck/p/17527972.html

相关文章

  • Hydro #4766. 文艺计算姬 题解--zhengjun
    link前置知识:Prufer序列,二分图别的题解都是直接给答案,没有比较易懂的思路。首先,考虑Prufer序列,发现右边点删除一定会加入一个左边点,另一边类似。且生成Prufer序列的最后一定会留下左右边各一个点。所以左边点在Prufer序列中出现的次数即为\(m-1\),右边即为\(n-1\)。......
  • 【Maven】Unknown lifecycle phase “.test.skip=true“.问题解决
    我们在运行跳过单元测试时的命令mvnpackage-Dmaven.test.skip=true时,出现Unknownlifecyclephase".test.skip=true".如下[ERROR]Unknownlifecyclephase".test.skip=true".Youmustspecifyavalidlifecyclephaseoragoalintheformat<plugin-prefix>......
  • PAT乙级【Java题解合集】
    ✨说在前面       这个暑假博主用大概两周不到的闲暇时间把PAT乙级的110道算法题全部肝完了,个人感觉题目的难度大部分在中等偏下,大概有二十道左右的题目还是蛮有意思的,值得细细去钻研,本专栏非常适合新手入门算法,也适合Java算法老手巩固一些基本知识点,由于C站上关于PAT乙级J......
  • 牛客练习赛 112 B~C题题解
    卡B题了,难受B.qsggandSubarrayB-qsggandSubarray_牛客练习赛112(nowcoder.com)题意给定一个长为n的序列,求有多少个子区间的按位与和为0。思路要想按位与之和为0,那么对于区间的所有数,每个二进制位都要有一个0。设f[i]表示二进制位i的最右边一个0出现的位置,枚举序列的每......
  • ABC306E 题解
    题目链接题目大意维护一个数据结构,数列长度为\(n\),\(q\)次操作,每次操作修改一个位置上的值,每次操作后输出数列里前\(k\)小的数的和(\(k\)是给定的)。\(n,k,q\leq5\times10^5\)值域\(1\times10^9\)题目分析开一棵权值线段树,每个节点储存对应区间的数的个数和数的和,......
  • ABC306F 题解
    题目链接题目大意对于\(S_1\capS_2=\emptyset\),定义长度为\(|S_1|+|S_2|\)的序列\(A\),为\(S_1\cupS_2\)排序后的结果。定义二元函数\(f(S_1,S_2)=\sum\limits_{1\leqi\leq|S_1|+|S_2|}i\times[A_i\inS_1]\)。给定\(n\)个大小为\(m\)的正整数集合\(S\)......
  • NOIP 模拟赛 2023.07.04 题解--zhengjun
    linkT1转化为\((b_i,a_i)\)与\((b_j,a_j)\)之间的斜率。发现性质(省略),只需要计算相邻两个点之间的答案即可,用set就行了。T2先找性质,发现即为\(a,b,c\)各有某一位是“独特”(即其他两个数这一位与之不一样)的。直接\(O(8^2n)\)记录各个状态,预处理转移优化一下即可。T......
  • 武汉理工大学第四届ACM校赛 部分题解
    比赛地址A.ST和TS回文问题题意:给出一个字符串s,进行q次操作,操作如下:1x:给字符串的末尾加上一个字符x2k:查询是否存在长度为k的字符串t,满足s+t==t+sSolution字符串哈希当k<n时,需检查s长度为k的前后缀是否相同,并且检查s长度为n-k的前后缀是否都是回文当k==n时,一定有解当k<......
  • 洛谷CF29B题解
    CF29B交通信号灯传送门题目很好理解,这里就不多说了,思路都在代码里#include<bits/stdc++.h>usingnamespacestd;doublel,d,v,g,r;intmain(){ cout<<fixed<<setprecision(8);//重置输出方式(保留8位小数) cin>>l>>d>>v>>g>>r; if(l<=d)cout<<......
  • P9431 [NAPC-#1] Stage3 - JRefreshers 题解
    传送门这个人赛时看错了几次题目导致样例调了1h。\(Sol1:n\leqslant10,T\leqslant10\)乱搞分。枚举跳跃的顺序,判断可不可行,最后取最大值,复杂度\(O((n-1)!)\)。\(Sol2:B\)感觉跟正解没什么关系,先说这个。特殊性质\(\mathbfB\):保证对于任意跳跃球\(u,v\),如......