HDOJ 5343 MZL's Circle Zhou 后缀自动机




对第二个串建SAM求出第二个串的以每个字符开头的不同子串的数目..

再对第一个串建SAM,遍历自动机如果某个节点后面没有某个字符则答案加上这个节点的出现次数乘上以这个字符为开头的在第二个串中的不同子串的数目..

MZL's Circle Zhou

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 244    Accepted Submission(s): 84


Problem Description
MZL's Circle Zhou is good at solving some counting problems. One day, he comes up with a counting problem:
You are given two strings  a,b  which consist of only lowercase English letters. You can subtract a substring  x  (maybe empty) from string  a  and a substring  y  (also maybe empty) from string  b , and then connect them as  x+y  with  x  at the front and  y  at the back. In this way, a series of new strings can be obtained.
The question is how many different new strings can be obtained in this way.
Two strings are different, if and only if they have different lengths or there exists an integer  i  such that the two strings have different characters at position  i .
 

Input
The first line of the input is a single integer  T (T5) , indicating the number of testcases. 
For each test case, there are two lines, the first line is string  a , and the second line is string  b 1<=|a|,|b|<=90000 .
 

Output
For each test case, output one line, a single integer indicating the answer.
 

Sample Input
  
  
2 acbcc cccabc bbbabbababbababbaaaabbbbabbaaaabaabbabbabbbaaabaab abbaabbabbaaaabbbaababbabbabababaaaaabbaabbaabbaab
 

Sample Output
  
  
135 557539
 

Author
SXYZ
 

Source
 

/* ***********************************************
Author        :CKboss
Created Time  :2015年08月26日 星期三 18时49分03秒
File Name     :HDOJ5343.cpp
************************************************ */

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <cmath>
#include <cstdlib>
#include <vector>
#include <queue>
#include <set>
#include <map>

using namespace std;

typedef unsigned long long int LL;

const int CHAR=26,maxn=200100;

struct SAM_Node
{
	SAM_Node *fa,*next[CHAR];
	int len,id,pos;
	SAM_Node(){}
	SAM_Node(int _len)
	{
		fa=0; len=_len;
		memset(next,0,sizeof(next));
	}
};

SAM_Node SAM_node[maxn],*SAM_root,*SAM_last;
int SAM_size;

SAM_Node *newSAM_Node(int len)
{
	SAM_node[SAM_size]=SAM_Node(len);
	SAM_node[SAM_size].id=SAM_size;
	return &SAM_node[SAM_size++];
}

SAM_Node *newSAM_Node(SAM_Node *p)
{
	SAM_node[SAM_size]=*p;
	SAM_node[SAM_size].id=SAM_size;
	return &SAM_node[SAM_size++];
}

void SAM_init()
{
	SAM_size=1;
	SAM_root=SAM_last=newSAM_Node(0);
	SAM_node[0].pos=0;
}

void SAM_add(int x,int len)
{
	SAM_Node *p=SAM_last,*np=newSAM_Node(p->len+1);
	np->pos=len; SAM_last=np;
	for(;p&&!p->next[x];p=p->fa)
		p->next[x]=np;
	if(!p)
	{
		np->fa=SAM_root; return ;
	}
	SAM_Node *q=p->next[x];
	if(q->len==p->len+1)
	{
		np->fa=q; return ;
	}
	SAM_Node *nq=newSAM_Node(q);
	nq->len=p->len+1;
	q->fa=nq; np->fa=nq;
	for(;p&&p->next[x]==q;p=p->fa)
		p->next[x]=nq;
}

int c[maxn],num[maxn];
SAM_Node* top[maxn];

void Count(char str[],int len)
{
	memset(c,0,sizeof(c));
	memset(num,0,sizeof(num));

	for(int i=0;i<SAM_size;i++) c[SAM_node[i].len]++;
	for(int i=1;i<=len;i++) c[i]+=c[i-1];
	for(int i=0;i<SAM_size;i++) top[--c[SAM_node[i].len]]=&SAM_node[i];

	SAM_Node *p=SAM_root;
	for(;p->len!=len;p=p->next[str[p->len]-'a']) num[p->id]=1;
	num[p->id]=1;

	for(int i=SAM_size-1;i>=0;i--)
	{
		p=top[i];
		if(p->fa)
		{
			SAM_Node *q=p->fa; num[q->id]+=num[p->id];
		}
	}
}

int len1,len2;
char str1[maxn],str2[maxn];
LL cum[maxn];
bool vis[maxn];


int dfs(int u)
{
	if(vis[u]) return num[u];
	vis[u]=true;
	int ret=1;
	for(int i=0;i<26;i++)
	{
		if(SAM_node[u].next[i])
		{
			ret+=dfs(SAM_node[u].next[i]->id);
		}
	}
	return num[u]=ret;
}

int main()
{
	//freopen("in.txt","r",stdin);
	//freopen("out.txt","w",stdout);

	int T_T;
	scanf("%d",&T_T);
	while(T_T--)
	{
		cin>>str1>>str2;
		len1=strlen(str1); len2=strlen(str2);
		SAM_init();
		for(int i=0;i<len2;i++)
			SAM_add(str2[i]-'a',i);
		memset(cum,0,sizeof(cum));
		memset(vis,false,sizeof(vis));
		dfs(1);
		LL ans=0;
		for(int i=0;i<26;i++) 
		{
			if(SAM_node[1].next[i])
			{
				cum[i]=num[SAM_node[1].next[i]->id];
			}
		}
		SAM_init();
		for(int i=0;i<len1;i++) SAM_add(str1[i]-'a',i);
		for(int i=2;i<SAM_size;i++)
		{
			if(SAM_node[i].fa)
			{
				LL l=SAM_node[i].len-SAM_node[i].fa->len;
				for(int j=0;j<26;j++)
				{
					if(SAM_node[i].next[j]==0) ans+=l*cum[j];
				}
				ans+=l;
			}
		}
		cout<<ans+1<<endl;
	}
    return 0;
}





  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值