CF1276F Asterisk Substrings


一、题目

点此看题

二、解法

肯定不能直接考虑带星号的母串,我们考虑最后的答案会长什么样子。

结合样例 \(1\),我们可以知道答案是这样几种情况:empty,*,s,*s,s*,s*t

\(5\) 种都好算到爆炸,就是本质不同的子串魔改一下就行了。

考虑最后一个怎么算,考虑两个本质不同的 s*t 要不然是 \(s\) 不同,要不然是 \(t\) 不同。所以相比于直接枚举前缀,我们可以枚举每一个 \(s\) 的等价类来保证 \(s\) 相同,这样就只需要处理 \(t\) 不同的条件了。

同一个等价类还有一个条件是出现位置相同,设这个等价类的出现位置为 \(p\),那么就是把 \(p_i+2\) 这些后缀全部取出来,我们有多少个本质不同后缀的前缀。这个可以放在 \(\tt sam\) 上解决,首先对反串建出后缀自动机,首先加上所有后缀的深度,然后考虑去重,把所有后缀按 \(\tt dfs\) 序排序,然后减去相邻两个 \(\tt lca\) 的深度即可。

要算所有 \(s\) 对应的 \(t\),可以考虑启发式合并,因为父亲能继承儿子的出现位置。我们用线段树维护反串的 \(\tt dfs\) 序,上传的时候就减去左儿子最右边的点和右儿子最左边的点的 \(\tt lca\) 的深度,那么时间复杂度 \(O(n\log n)\)

代码给我打吐了,看来是好久没写毒瘤码力下降了。

#include 
#include 
#include 
#include 
using namespace std;
const int M = 200005;
const int N = 30*M;
#define ll long long
int read()
{
	int x=0,f=1;char c;
	while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
	while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
	return x*f;
}
int n,m,Ind,cnt,dp[2*M][20],lg[2*M],st[M],dep[M],rt[M];
int p1[M],p2[M],ls[N],rs[N],ml[N],mr[N];char s[M];
ll ans,sum[N];
struct node
{
	int fa,len,ch[26];
};
int Min(int x,int y)
{
	return dep[x]>1;
	if(mid>=id) ins(ls[x],l,mid,id);
	else ins(rs[x],mid+1,r,id);
	up(x);
}
struct Sam
{
	int cnt,last;node a[M];vector g[M];
	Sam() {cnt=last=1;}
	void add(int c)
	{
	    int p=last,np=last=++cnt;
	    a[np].len=a[p].len+1;
	    for(;p && !a[p].ch[c];p=a[p].fa) a[p].ch[c]=np;
	    if(!p) a[np].fa=1;
	    else
	    {
	        int q=a[p].ch[c];
	        if(a[q].len==a[p].len+1) a[np].fa=q;
	        else
	        {
	            int nq=++cnt;
	            a[nq]=a[q];a[nq].len=a[p].len+1;
	            a[q].fa=a[np].fa=nq;
	            for(;p && a[p].ch[c]==q;p=a[p].fa) a[p].ch[c]=nq;
	        }
	    }
	}
	void build()
	{
		for(int i=2;i<=cnt;i++)
		{
			int j=a[i].fa;
			g[j].push_back(i);
		}
	}
	//the second sam
	void dfs(int u,int fa)
	{
		dep[u]=a[u].len;
		st[u]=++Ind;dp[Ind][0]=u;
		for(int i=0;i>1]+1;
	}
	//the first sam
	void work(int u)
	{
		for(int i=0;i=1;i--)
	{
		B.add(s[i]-'a');p2[i]=B.last;
		if(i>1) ans+=B.a[p2[i]].len-B.a[B.a[p2[i]].fa].len;
	}
	ans+=2;
	A.build();B.build();B.init();
	for(int i=1;i

相关