1. 程式人生 > 實用技巧 >hihoCoder1457 字尾自動機四·重複旋律7

hihoCoder1457 字尾自動機四·重複旋律7

字尾自動機

在後綴自動機上拓撲,計算每個節點的答案即可

然而我涼了很久……

原因:建圖陣列開小了!

注意:字尾自動機節點數開\(2n\),邊的條數開\(3n\)

C++ Code:

#include<bits/stdc++.h>
#define N 3000005
#define mod 1000000007
#define int long long
using namespace std;
int n,T,cnt=1,last=1,t[N][11],pre[N],sz[N],len[N],rd[N];
int tot,head[N],nxt[N],d[N],d2[N],p[N],g[N];
char s[N];
char s1[1];
long long z[N],ans;
queue<int>q;
void ins(char *s)
{
	n=strlen(s);
	for (int i=0;i<n;i++)
	{
		int c=(int)(s[i]-'0');
		int p,q,np=++cnt;
		len[np]=len[last]+1;
		for (p=last;p&&!t[p][c];p=pre[p])
			t[p][c]=np;
		if (!p)
			pre[np]=1; else
			{
				q=t[p][c];
				if (len[p]+1==len[q])
					pre[np]=q; else
					{
						
						cnt++;
						len[cnt]=len[p]+1;
						for (int j=0;j<11;j++)
							t[cnt][j]=t[q][j];
						pre[cnt]=pre[q];
						for (;p&&t[p][c]==q;p=pre[p])
							t[p][c]=cnt;
						pre[q]=pre[np]=cnt;
					}
			}
		last=np;
	}
}
void add(int x,int y,int w)
{
	tot++;
	d[tot]=y;
	d2[tot]=w;
	nxt[tot]=head[x];
	head[x]=tot;
	rd[y]++;
}
main() 
{
	scanf("%lld",&T);
	z[1]=0;
	s1[0]=':';
	for (int i=1;i<=T;i++)
	{
		scanf("%s",s);
		ins(s);
		if (i^T)
			ins(s1);
	}
	for (int i=1;i<=cnt;i++)
		head[i]=0,rd[i]=0;
	for (int i=1;i<=cnt;i++)
		for (int j=0;j<10;j++)
			if (t[i][j])
				add(i,t[i][j],j);
	sz[1]=1;
	for (int i=1;i<=cnt;i++)
		if (!rd[i])
			q.push(i);
	while (!q.empty())
	{
		int u=q.front();
		q.pop();
		for (int i=head[u];i;i=nxt[i])
		{
			int v=d[i];
			long long cost=d2[i];
			rd[v]--;
			z[v]+=z[u]*10+cost*sz[u],z[v]%=mod,sz[v]+=sz[u];
			if (!rd[v])
			{
				ans+=z[v];
				ans%=mod;
				q.push(v);
			}
		}
	}
	cout << ans << endl;
	return 0;
}