COGS传送门

用SAM重新写了一遍..

我的方法比较笨,先把两个串连在一起,算出来相同子串个数,同理算出s1和s2的子串个数。作差即可。

至于如何统计子串个数,首先toposort后搞出right集的大小,然后$C_{|right|}^{2} \times (step[i]-step[fa])$就是答案。

//BZOJ 4565
//by Cydiater
//2017.1.21
#include <iostream>
#include <cmath>
#include <cstring>
#include <string>
#include <queue>
#include <map>
#include <ctime>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <bitset>
#include <set>
#include <vector>
using namespace std;
#define ll long long
#define up(i,j,n)	for(int i=j;i<=n;i++)
#define down(i,j,n)	for(int i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
#define FILE		"find_2016"
const int MAXN=1e6+5;
const int oo=0x3f3f3f3f;
char s1[MAXN],s2[MAXN],s[MAXN];
int len1,len2;
struct SAM{
	int now,cnt,son[MAXN][30],step[MAXN],pre[MAXN],rnk[MAXN],label[MAXN];
	ll g[MAXN],ans;
	SAM(){now=1;cnt=1;}
	void Extend(int nxt){
		int p=now,np=++cnt;now=np;g[np]=1;
		step[np]=step[p]+1;
		for(;p&&!son[p][nxt];p=pre[p])son[p][nxt]=np;
		if(!p)pre[np]=1;
		else{
			int q=son[p][nxt],nq;
			if(step[q]==step[p]+1)pre[np]=q;
			else{
				step[(nq=++cnt)]=step[p]+1;
				memcpy(son[nq],son[q],sizeof(son[q]));
				pre[nq]=pre[q];
				pre[np]=pre[q]=nq;
				for(;son[p][nxt]==q;p=pre[p])son[p][nxt]=nq;
			}
		}
	}
	void Build(int len){
		up(i,1,len)Extend(s[i]-'a');
	}
	void Clear(){
		now=cnt=1;
		memset(pre,0,sizeof(pre));
		memset(son,0,sizeof(son));
		memset(step,0,sizeof(step));
		memset(g,0,sizeof(g));
		memset(label,0,sizeof(label));
		memset(rnk,0,sizeof(rnk));
	}
	ll col(int len){
		//topsort
		ans=0;
		up(i,1,cnt)label[step[i]]++;
		up(i,1,len)label[i]+=label[i-1];
		up(i,1,cnt)rnk[label[step[i]]--]=i;
		down(i,cnt,2){
			int node=rnk[i];
			if(g[node]>=2)
				ans+=(g[node]*(g[node]-1)>>1)*(ll)(step[node]-step[pre[node]]);
			g[pre[node]]+=g[node];
		}
		return ans;
	}
}sam;
namespace solution{
	void Prepare(){
		scanf("%s",s1+1);
		len1=strlen(s1+1);
		scanf("%s",s2+1);
		len2=strlen(s2+1);
	}
	void Solve(){
		ll ans1,ans2,ans3;
		memcpy(s,s1,sizeof(s));
		sam.Build(len1);
		ans1=sam.col(len1);
		sam.Clear();
		memcpy(s,s2,sizeof(s));
		sam.Build(len2);
		ans2=sam.col(len2);
		sam.Clear();

		memcpy(s,s1,sizeof(s));
		s[len1+1]='a'+26;
		up(i,len1+2,len1+len2+1)s[i]=s2[i-len1-1];
		sam.Build(len1+len2+1);
		ans3=sam.col(len1+len2+1);
		//cout<<ans1<<' '<<ans2<<' '<<ans3<<endl;
		ans3-=ans1+ans2;
		cout<<ans3<<endl;
	}
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	using namespace solution;
	Prepare();
	Solve();
	return 0;
}

看了看别人用SAM实现的代码,发现其实不必要那样。对于s1建一个sam,统计每个点的路径对应多少个子串。然后s2串在SAM上跑,经过一个点就统计上父亲点的sum(因为变换了位置)再加上当前对应的字符串的数量就行了。

[BZOJ4566][HAOI2016]找相同子串的更多相关文章

  1. BZOJ4566 [Haoi2016]找相同字符【SAM】

    BZOJ4566 [Haoi2016]找相同字符 给定两个字符串\(s和t\),要求找出两个字符串中所有可以相互匹配的子串对的数量 首先考虑可以怎么做,我们可以枚举\(t\)串的前缀\(t'\),然后 ...

  2. 字符串(后缀数组):HAOI2016 找相同子串

    [HAOI2016]找相同子串 [题目描述] 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两个子串中有一个位置不同. [输入格式] 两行,两个字符 ...

  3. [BZOJ4566][Haoi2016]找相同字符 后缀自动机+dp

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 1212  Solved: 694[Submit][Stat ...

  4. [Bzoj4566][Haoi2016]找相同字符(广义后缀自动机)

    4566: [Haoi2016]找相同字符 Time Limit: 20 Sec  Memory Limit: 256 MBSubmit: 861  Solved: 495[Submit][Statu ...

  5. BZOJ4566: [Haoi2016]找相同字符

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  6. BZOJ4566 [Haoi2016]找相同字符 字符串 SAM

    原文链接https://www.cnblogs.com/zhouzhendong/p/BZOJ4566.html 题目传送门 - BZOJ4566 题意 给定两个字符串 $s1$ 和 $s2$ ,问有 ...

  7. BZOJ4566 Haoi2016 找相同字符【广义后缀自动机】

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  8. BZOJ4566:[HAOI2016]找相同字符(SAM)

    Description 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. Input 两行,两个字符串s1,s2,长度分别 ...

  9. BZOJ4566 [Haoi2016]找相同字符 【后缀数组】

    题目 给定两个字符串,求出在两个字符串中各取出一个子串使得这两个子串相同的方案数.两个方案不同当且仅当这两 个子串中有一个位置不同. 输入格式 两行,两个字符串s1,s2,长度分别为n1,n2.1 & ...

随机推荐

  1. powerdesigner 修改name时code不修改

    o

  2. Java IO 修改文件名

    /** *//**文件重命名 * @param path 文件目录 * @param oldname 原来的文件名 * @param newname 新文件名 */ public void renam ...

  3. python--get_data_from_csv_or_txt

    一.从csv文件中获取 import osimport csv class GetDataFromCsvFile(): def __init__(self, csv_file, params_list ...

  4. Spark源码分析 – SchedulerBackend

    SchedulerBackend, 两个任务, 申请资源和task执行和管理 对于SparkDeploySchedulerBackend, 基于actor模式, 主要就是启动和管理两个actor De ...

  5. Ubuntu下载及安装

    Ubuntu(友帮拓.优般图.乌班图)是一个以桌面应用为主的开源GNU/Linux操作系统,Ubuntu 是基于DebianGNU/Linux,支持x86.amd64(即x64)和ppc架构,由全球化 ...

  6. CDH部署日志

    CDH部署时出现如图所示的错误 可去服务器查看:/opt/cm-5.5.0/run/cloudera-scm-agent/process/ccdeploy_hbase-conf_etchbasecon ...

  7. Flask用Flask-SQLAlchemy连接MySQL

    安装 pip3 install Flask-SQLAlchemy 测试环境目录结构 settings.py DIALECT = 'mysql' DRIVER = 'pymysql' USERNAME ...

  8. Node.js REST 工具 Restify

    Restify 是一个 Node.JS 模块,可以让你创建正确的 REST web services.它借鉴了很多 express 的设计,因为它是 node.js web 应用事实上的标准 API. ...

  9. DOM扩展学习笔记

    对DOM的两个主要扩展是Selectors API(选择符API)和HTML5,还有一个不太瞩目的Element Traversal元素遍历规范为DOM添加了一些属性,另外还有一些专有扩展. 选择符A ...

  10. 模块讲解----json与pickle模块的区别

    1.在生产中,dumps和loads只进行一次,而且要用w把原来的数据冲掉,从而保证每次都是最新的. 2.虚拟机的快照,是每个快照都有一个文件,而不是全都不放在一起. 3.如果想生产好几个序列化,就生 ...